]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/loclikely.cpp
ICU-64252.0.1.tar.gz
[apple/icu.git] / icuSources / common / loclikely.cpp
index effa646dd68fd098d77d396df7476956deb13814..2f64e104b58254a8b9fe5e2bc83ad779c760e890 100644 (file)
@@ -1,3 +1,5 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
 *
@@ -6,7 +8,7 @@
 *
 *******************************************************************************
 *   file name:  loclikely.cpp
-*   encoding:   US-ASCII
+*   encoding:   UTF-8
 *   tab size:   8 (not used)
 *   indentation:4
 *
 *   that then do not depend on resource bundle code and likely-subtags data.
 */
 
+#include "unicode/bytestream.h"
 #include "unicode/utypes.h"
 #include "unicode/locid.h"
 #include "unicode/putil.h"
+#include "unicode/uchar.h"
 #include "unicode/uloc.h"
 #include "unicode/ures.h"
 #include "unicode/uscript.h"
+#include "bytesinkutil.h"
+#include "charstr.h"
 #include "cmemory.h"
 #include "cstring.h"
 #include "ulocimp.h"
 #include "ustr_imp.h"
 
+/**
+ * These are the canonical strings for unknown languages, scripts and regions.
+ **/
+static const char* const unknownLanguage = "und";
+static const char* const unknownScript = "Zzzz";
+static const char* const unknownRegion = "ZZ";
+
 /**
  * This function looks for the localeID in the likelySubtags resource.
  *
@@ -47,9 +60,22 @@ findLikelySubtags(const char* localeID,
         int32_t resLen = 0;
         const UChar* s = NULL;
         UErrorCode tmpErr = U_ZERO_ERROR;
-        UResourceBundle* subtags = ures_openDirect(NULL, "likelySubtags", &tmpErr);
+        icu::LocalUResourceBundlePointer subtags(ures_openDirect(NULL, "likelySubtags", &tmpErr));
         if (U_SUCCESS(tmpErr)) {
-            s = ures_getStringByKey(subtags, localeID, &resLen, &tmpErr);
+            icu::CharString und;
+            if (localeID != NULL) {
+                if (*localeID == '\0') {
+                    localeID = unknownLanguage;
+                } else if (*localeID == '_') {
+                    und.append(unknownLanguage, *err);
+                    und.append(localeID, *err);
+                    if (U_FAILURE(*err)) {
+                        return NULL;
+                    }
+                    localeID = und.data();
+                }
+            }
+            s = ures_getStringByKey(subtags.getAlias(), localeID, &resLen, &tmpErr);
 
             if (U_FAILURE(tmpErr)) {
                 /*
@@ -68,8 +94,6 @@ findLikelySubtags(const char* localeID,
                 u_UCharsToChars(s, buffer, resLen + 1);
                 result = buffer;
             }
-
-            ures_close(subtags);
         } else {
             *err = tmpErr;
         }
@@ -108,13 +132,6 @@ appendTag(
     *bufferLength += tagLength;
 }
 
-/**
- * These are the canonical strings for unknown languages, scripts and regions.
- **/
-static const char* const unknownLanguage = "und";
-static const char* const unknownScript = "Zzzz";
-static const char* const unknownRegion = "ZZ";
-
 /**
  * Create a tag string from the supplied parameters.  The lang, script and region
  * parameters may be NULL pointers. If they are, their corresponding length parameters
@@ -144,12 +161,10 @@ static const char* const unknownRegion = "ZZ";
  * @param trailing Any trailing data to append to the new tag.
  * @param trailingLength The length of the trailing data.
  * @param alternateTags A string containing any alternate tags.
- * @param tag The output buffer.
- * @param tagCapacity The capacity of the output buffer.
+ * @param sink The output sink receiving the tag string.
  * @param err A pointer to a UErrorCode for error reporting.
- * @return The length of the tag string, which may be greater than tagCapacity, or -1 on error.
  **/
-static int32_t U_CALLCONV
+static void U_CALLCONV
 createTagStringWithAlternates(
     const char* lang,
     int32_t langLength,
@@ -160,16 +175,13 @@ createTagStringWithAlternates(
     const char* trailing,
     int32_t trailingLength,
     const char* alternateTags,
-    char* tag,
-    int32_t tagCapacity,
+    icu::ByteSink& sink,
     UErrorCode* err) {
 
     if (U_FAILURE(*err)) {
         goto error;
     }
-    else if (tag == NULL ||
-             tagCapacity <= 0 ||
-             langLength >= ULOC_LANG_CAPACITY ||
+    else if (langLength >= ULOC_LANG_CAPACITY ||
              scriptLength >= ULOC_SCRIPT_CAPACITY ||
              regionLength >= ULOC_COUNTRY_CAPACITY) {
         goto error;
@@ -183,7 +195,6 @@ createTagStringWithAlternates(
          **/
         char tagBuffer[ULOC_FULLNAME_CAPACITY];
         int32_t tagLength = 0;
-        int32_t capacityRemaining = tagCapacity;
         UBool regionAppended = FALSE;
 
         if (langLength > 0) {
@@ -310,55 +321,28 @@ createTagStringWithAlternates(
             }
         }
 
-        {
-            const int32_t toCopy =
-                tagLength >= tagCapacity ? tagCapacity : tagLength;
-
-            /**
-             * Copy the partial tag from our internal buffer to the supplied
-             * target.
-             **/
-            uprv_memcpy(
-                tag,
-                tagBuffer,
-                toCopy);
-
-            capacityRemaining -= toCopy;
-        }
+        /**
+         * Copy the partial tag from our internal buffer to the supplied
+         * target.
+         **/
+        sink.Append(tagBuffer, tagLength);
 
         if (trailingLength > 0) {
-            if (*trailing != '@' && capacityRemaining > 0) {
-                tag[tagLength++] = '_';
-                --capacityRemaining;
-                if (capacityRemaining > 0 && !regionAppended) {
+            if (*trailing != '@') {
+                sink.Append("_", 1);
+                if (!regionAppended) {
                     /* extra separator is required */
-                    tag[tagLength++] = '_';
-                    --capacityRemaining;
+                    sink.Append("_", 1);
                 }
             }
 
-            if (capacityRemaining > 0) {
-                /*
-                 * Copy the trailing data into the supplied buffer.  Use uprv_memmove, since we
-                 * don't know if the user-supplied buffers overlap.
-                 */
-                const int32_t toCopy =
-                    trailingLength >= capacityRemaining ? capacityRemaining : trailingLength;
-
-                uprv_memmove(
-                    &tag[tagLength],
-                    trailing,
-                    toCopy);
-            }
+            /*
+             * Copy the trailing data into the supplied buffer.
+             */
+            sink.Append(trailing, trailingLength);
         }
 
-        tagLength += trailingLength;
-
-        return u_terminateChars(
-                    tag,
-                    tagCapacity,
-                    tagLength,
-                    err);
+        return;
     }
 
 error:
@@ -372,8 +356,6 @@ error:
         U_SUCCESS(*err)) {
         *err = U_ILLEGAL_ARGUMENT_ERROR;
     }
-
-    return -1;
 }
 
 /**
@@ -397,12 +379,10 @@ error:
  * @param regionLength The length of the region tag.
  * @param trailing Any trailing data to append to the new tag.
  * @param trailingLength The length of the trailing data.
- * @param tag The output buffer.
- * @param tagCapacity The capacity of the output buffer.
+ * @param sink The output sink receiving the tag string.
  * @param err A pointer to a UErrorCode for error reporting.
- * @return The length of the tag string, which may be greater than tagCapacity.
  **/
-static int32_t U_CALLCONV
+static void U_CALLCONV
 createTagString(
     const char* lang,
     int32_t langLength,
@@ -412,11 +392,10 @@ createTagString(
     int32_t regionLength,
     const char* trailing,
     int32_t trailingLength,
-    char* tag,
-    int32_t tagCapacity,
+    icu::ByteSink& sink,
     UErrorCode* err)
 {
-    return createTagStringWithAlternates(
+    createTagStringWithAlternates(
                 lang,
                 langLength,
                 script,
@@ -426,8 +405,7 @@ createTagString(
                 trailing,
                 trailingLength,
                 NULL,
-                tag,
-                tagCapacity,
+                sink,
                 err);
 }
 
@@ -508,7 +486,7 @@ parseTagString(
             unknownLanguage);
         *langLength = (int32_t)uprv_strlen(lang);
     }
-    else if (_isIDSeparator(*position)) {
+    if (_isIDSeparator(*position)) {
         ++position;
     }
 
@@ -575,7 +553,7 @@ error:
     goto exit;
 }
 
-static int32_t U_CALLCONV
+static UBool U_CALLCONV
 createLikelySubtagsString(
     const char* lang,
     int32_t langLength,
@@ -585,17 +563,14 @@ createLikelySubtagsString(
     int32_t regionLength,
     const char* variants,
     int32_t variantsLength,
-    char* tag,
-    int32_t tagCapacity,
-    UErrorCode* err)
-{
+    icu::ByteSink& sink,
+    UErrorCode* err) {
     /**
      * ULOC_FULLNAME_CAPACITY will provide enough capacity
      * that we can build a string that contains the language,
      * script and region code without worrying about overrunning
      * the user-supplied buffer.
      **/
-    char tagBuffer[ULOC_FULLNAME_CAPACITY];
     char likelySubtagsBuffer[ULOC_FULLNAME_CAPACITY];
 
     if(U_FAILURE(*err)) {
@@ -609,25 +584,28 @@ createLikelySubtagsString(
 
         const char* likelySubtags = NULL;
 
-        createTagString(
-            lang,
-            langLength,
-            script,
-            scriptLength,
-            region,
-            regionLength,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
+            createTagString(
+                lang,
+                langLength,
+                script,
+                scriptLength,
+                region,
+                regionLength,
+                NULL,
+                0,
+                sink,
+                err);
+        }
         if(U_FAILURE(*err)) {
             goto error;
         }
 
         likelySubtags =
             findLikelySubtags(
-                tagBuffer,
+                tagBuffer.data(),
                 likelySubtagsBuffer,
                 sizeof(likelySubtagsBuffer),
                 err);
@@ -639,7 +617,7 @@ createLikelySubtagsString(
             /* Always use the language tag from the
                maximal string, since it may be more
                specific than the one provided. */
-            return createTagStringWithAlternates(
+            createTagStringWithAlternates(
                         NULL,
                         0,
                         NULL,
@@ -649,9 +627,9 @@ createLikelySubtagsString(
                         variants,
                         variantsLength,
                         likelySubtags,
-                        tag,
-                        tagCapacity,
+                        sink,
                         err);
+            return TRUE;
         }
     }
 
@@ -662,25 +640,28 @@ createLikelySubtagsString(
 
         const char* likelySubtags = NULL;
 
-        createTagString(
-            lang,
-            langLength,
-            script,
-            scriptLength,
-            NULL,
-            0,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
+            createTagString(
+                lang,
+                langLength,
+                script,
+                scriptLength,
+                NULL,
+                0,
+                NULL,
+                0,
+                sink,
+                err);
+        }
         if(U_FAILURE(*err)) {
             goto error;
         }
 
         likelySubtags =
             findLikelySubtags(
-                tagBuffer,
+                tagBuffer.data(),
                 likelySubtagsBuffer,
                 sizeof(likelySubtagsBuffer),
                 err);
@@ -692,7 +673,7 @@ createLikelySubtagsString(
             /* Always use the language tag from the
                maximal string, since it may be more
                specific than the one provided. */
-            return createTagStringWithAlternates(
+            createTagStringWithAlternates(
                         NULL,
                         0,
                         NULL,
@@ -702,9 +683,9 @@ createLikelySubtagsString(
                         variants,
                         variantsLength,
                         likelySubtags,
-                        tag,
-                        tagCapacity,
+                        sink,
                         err);
+            return TRUE;
         }
     }
 
@@ -715,25 +696,28 @@ createLikelySubtagsString(
 
         const char* likelySubtags = NULL;
 
-        createTagString(
-            lang,
-            langLength,
-            NULL,
-            0,
-            region,
-            regionLength,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
+            createTagString(
+                lang,
+                langLength,
+                NULL,
+                0,
+                region,
+                regionLength,
+                NULL,
+                0,
+                sink,
+                err);
+        }
         if(U_FAILURE(*err)) {
             goto error;
         }
 
         likelySubtags =
             findLikelySubtags(
-                tagBuffer,
+                tagBuffer.data(),
                 likelySubtagsBuffer,
                 sizeof(likelySubtagsBuffer),
                 err);
@@ -745,7 +729,7 @@ createLikelySubtagsString(
             /* Always use the language tag from the
                maximal string, since it may be more
                specific than the one provided. */
-            return createTagStringWithAlternates(
+            createTagStringWithAlternates(
                         NULL,
                         0,
                         script,
@@ -755,9 +739,9 @@ createLikelySubtagsString(
                         variants,
                         variantsLength,
                         likelySubtags,
-                        tag,
-                        tagCapacity,
+                        sink,
                         err);
+            return TRUE;
         }
     }
 
@@ -767,25 +751,28 @@ createLikelySubtagsString(
     {
         const char* likelySubtags = NULL;
 
-        createTagString(
-            lang,
-            langLength,
-            NULL,
-            0,
-            NULL,
-            0,
-            NULL,
-            0,
-            tagBuffer,
-            sizeof(tagBuffer),
-            err);
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
+            createTagString(
+                lang,
+                langLength,
+                NULL,
+                0,
+                NULL,
+                0,
+                NULL,
+                0,
+                sink,
+                err);
+        }
         if(U_FAILURE(*err)) {
             goto error;
         }
 
         likelySubtags =
             findLikelySubtags(
-                tagBuffer,
+                tagBuffer.data(),
                 likelySubtagsBuffer,
                 sizeof(likelySubtagsBuffer),
                 err);
@@ -797,7 +784,7 @@ createLikelySubtagsString(
             /* Always use the language tag from the
                maximal string, since it may be more
                specific than the one provided. */
-            return createTagStringWithAlternates(
+            createTagStringWithAlternates(
                         NULL,
                         0,
                         script,
@@ -807,17 +794,13 @@ createLikelySubtagsString(
                         variants,
                         variantsLength,
                         likelySubtags,
-                        tag,
-                        tagCapacity,
+                        sink,
                         err);
+            return TRUE;
         }
     }
 
-    return u_terminateChars(
-                tag,
-                tagCapacity,
-                0,
-                err);
+    return FALSE;
 
 error:
 
@@ -825,7 +808,7 @@ error:
         *err = U_ILLEGAL_ARGUMENT_ERROR;
     }
 
-    return -1;
+    return FALSE;
 }
 
 #define CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength) \
@@ -847,12 +830,10 @@ error:
         } \
     }
 
-static int32_t
-_uloc_addLikelySubtags(const char*    localeID,
-         char* maximizedLocaleID,
-         int32_t maximizedLocaleIDCapacity,
-         UErrorCode* err)
-{
+static void
+_uloc_addLikelySubtags(const char* localeID,
+                       icu::ByteSink& sink,
+                       UErrorCode* err) {
     char lang[ULOC_LANG_CAPACITY];
     int32_t langLength = sizeof(lang);
     char script[ULOC_SCRIPT_CAPACITY];
@@ -862,14 +843,12 @@ _uloc_addLikelySubtags(const char*    localeID,
     const char* trailing = "";
     int32_t trailingLength = 0;
     int32_t trailingIndex = 0;
-    int32_t resultLength = 0;
+    UBool success = FALSE;
 
     if(U_FAILURE(*err)) {
         goto error;
     }
-    else if (localeID == NULL ||
-             maximizedLocaleID == NULL ||
-             maximizedLocaleIDCapacity <= 0) {
+    if (localeID == NULL) {
         goto error;
     }
 
@@ -900,7 +879,7 @@ _uloc_addLikelySubtags(const char*    localeID,
 
     CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength);
 
-    resultLength =
+    success =
         createLikelySubtagsString(
             lang,
             langLength,
@@ -910,55 +889,32 @@ _uloc_addLikelySubtags(const char*    localeID,
             regionLength,
             trailing,
             trailingLength,
-            maximizedLocaleID,
-            maximizedLocaleIDCapacity,
+            sink,
             err);
 
-    if (resultLength == 0) {
+    if (!success) {
         const int32_t localIDLength = (int32_t)uprv_strlen(localeID);
 
         /*
          * If we get here, we need to return localeID.
          */
-        uprv_memcpy(
-            maximizedLocaleID,
-            localeID,
-            localIDLength <= maximizedLocaleIDCapacity ? 
-                localIDLength : maximizedLocaleIDCapacity);
-
-        resultLength =
-            u_terminateChars(
-                maximizedLocaleID,
-                maximizedLocaleIDCapacity,
-                localIDLength,
-                err);
+        sink.Append(localeID, localIDLength);
     }
 
-    return resultLength;
+    return;
 
 error:
 
     if (!U_FAILURE(*err)) {
         *err = U_ILLEGAL_ARGUMENT_ERROR;
     }
-
-    return -1;
 }
 
-static int32_t
-_uloc_minimizeSubtags(const char*    localeID,
-         char* minimizedLocaleID,
-         int32_t minimizedLocaleIDCapacity,
-         UErrorCode* err)
-{
-    /**
-     * ULOC_FULLNAME_CAPACITY will provide enough capacity
-     * that we can build a string that contains the language,
-     * script and region code without worrying about overrunning
-     * the user-supplied buffer.
-     **/
-    char maximizedTagBuffer[ULOC_FULLNAME_CAPACITY];
-    int32_t maximizedTagBufferLength = sizeof(maximizedTagBuffer);
+static void
+_uloc_minimizeSubtags(const char* localeID,
+                      icu::ByteSink& sink,
+                      UErrorCode* err) {
+    icu::CharString maximizedTagBuffer;
 
     char lang[ULOC_LANG_CAPACITY];
     int32_t langLength = sizeof(lang);
@@ -973,9 +929,7 @@ _uloc_minimizeSubtags(const char*    localeID,
     if(U_FAILURE(*err)) {
         goto error;
     }
-    else if (localeID == NULL ||
-             minimizedLocaleID == NULL ||
-             minimizedLocaleIDCapacity <= 0) {
+    else if (localeID == NULL) {
         goto error;
     }
 
@@ -1008,32 +962,32 @@ _uloc_minimizeSubtags(const char*    localeID,
 
     CHECK_TRAILING_VARIANT_SIZE(trailing, trailingLength);
 
-    createTagString(
-        lang,
-        langLength,
-        script,
-        scriptLength,
-        region,
-        regionLength,
-        NULL,
-        0,
-        maximizedTagBuffer,
-        maximizedTagBufferLength,
-        err);
-    if(U_FAILURE(*err)) {
-        goto error;
-    }
+    {
+        icu::CharString base;
+        {
+            icu::CharStringByteSink sink(&base);
+            createTagString(
+                lang,
+                langLength,
+                script,
+                scriptLength,
+                region,
+                regionLength,
+                NULL,
+                0,
+                sink,
+                err);
+        }
 
-    /**
-     * First, we need to first get the maximization
-     * from AddLikelySubtags.
-     **/
-    maximizedTagBufferLength =
-        uloc_addLikelySubtags(
-            maximizedTagBuffer,
-            maximizedTagBuffer,
-            maximizedTagBufferLength,
-            err);
+        /**
+         * First, we need to first get the maximization
+         * from AddLikelySubtags.
+         **/
+        {
+            icu::CharStringByteSink sink(&maximizedTagBuffer);
+            ulocimp_addLikelySubtags(base.data(), sink, err);
+        }
+    }
 
     if(U_FAILURE(*err)) {
         goto error;
@@ -1043,9 +997,9 @@ _uloc_minimizeSubtags(const char*    localeID,
      * Start first with just the language.
      **/
     {
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-
-        const int32_t tagBufferLength =
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
             createLikelySubtagsString(
                 lang,
                 langLength,
@@ -1055,19 +1009,19 @@ _uloc_minimizeSubtags(const char*    localeID,
                 0,
                 NULL,
                 0,
-                tagBuffer,
-                sizeof(tagBuffer),
+                sink,
                 err);
+        }
 
         if(U_FAILURE(*err)) {
             goto error;
         }
         else if (uprv_strnicmp(
-                    maximizedTagBuffer,
-                    tagBuffer,
-                    tagBufferLength) == 0) {
+                    maximizedTagBuffer.data(),
+                    tagBuffer.data(),
+                    tagBuffer.length()) == 0) {
 
-            return createTagString(
+            createTagString(
                         lang,
                         langLength,
                         NULL,
@@ -1076,9 +1030,9 @@ _uloc_minimizeSubtags(const char*    localeID,
                         0,
                         trailing,
                         trailingLength,
-                        minimizedLocaleID,
-                        minimizedLocaleIDCapacity,
+                        sink,
                         err);
+            return;
         }
     }
 
@@ -1087,9 +1041,9 @@ _uloc_minimizeSubtags(const char*    localeID,
      **/
     if (regionLength > 0) {
 
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-
-        const int32_t tagBufferLength =
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
             createLikelySubtagsString(
                 lang,
                 langLength,
@@ -1099,19 +1053,19 @@ _uloc_minimizeSubtags(const char*    localeID,
                 regionLength,
                 NULL,
                 0,
-                tagBuffer,
-                sizeof(tagBuffer),
+                sink,
                 err);
+        }
 
         if(U_FAILURE(*err)) {
             goto error;
         }
         else if (uprv_strnicmp(
-                    maximizedTagBuffer,
-                    tagBuffer,
-                    tagBufferLength) == 0) {
+                    maximizedTagBuffer.data(),
+                    tagBuffer.data(),
+                    tagBuffer.length()) == 0) {
 
-            return createTagString(
+            createTagString(
                         lang,
                         langLength,
                         NULL,
@@ -1120,9 +1074,9 @@ _uloc_minimizeSubtags(const char*    localeID,
                         regionLength,
                         trailing,
                         trailingLength,
-                        minimizedLocaleID,
-                        minimizedLocaleIDCapacity,
+                        sink,
                         err);
+            return;
         }
     }
 
@@ -1132,9 +1086,9 @@ _uloc_minimizeSubtags(const char*    localeID,
      * maximal version that we already have.
      **/
     if (scriptLength > 0 && regionLength > 0) {
-        char tagBuffer[ULOC_FULLNAME_CAPACITY];
-
-        const int32_t tagBufferLength =
+        icu::CharString tagBuffer;
+        {
+            icu::CharStringByteSink sink(&tagBuffer);
             createLikelySubtagsString(
                 lang,
                 langLength,
@@ -1144,19 +1098,19 @@ _uloc_minimizeSubtags(const char*    localeID,
                 0,
                 NULL,
                 0,
-                tagBuffer,
-                sizeof(tagBuffer),
+                sink,
                 err);
+        }
 
         if(U_FAILURE(*err)) {
             goto error;
         }
         else if (uprv_strnicmp(
-                    maximizedTagBuffer,
-                    tagBuffer,
-                    tagBufferLength) == 0) {
+                    maximizedTagBuffer.data(),
+                    tagBuffer.data(),
+                    tagBuffer.length()) == 0) {
 
-            return createTagString(
+            createTagString(
                         lang,
                         langLength,
                         script,
@@ -1165,9 +1119,9 @@ _uloc_minimizeSubtags(const char*    localeID,
                         0,
                         trailing,
                         trailingLength,
-                        minimizedLocaleID,
-                        minimizedLocaleIDCapacity,
+                        sink,
                         err);
+            return;
         }
     }
 
@@ -1176,18 +1130,8 @@ _uloc_minimizeSubtags(const char*    localeID,
          * If we got here, return the locale ID parameter.
          **/
         const int32_t localeIDLength = (int32_t)uprv_strlen(localeID);
-
-        uprv_memcpy(
-            minimizedLocaleID,
-            localeID,
-            localeIDLength <= minimizedLocaleIDCapacity ? 
-                localeIDLength : minimizedLocaleIDCapacity);
-
-        return u_terminateChars(
-                    minimizedLocaleID,
-                    minimizedLocaleIDCapacity,
-                    localeIDLength,
-                    err);
+        sink.Append(localeID, localeIDLength);
+        return;
     }
 
 error:
@@ -1195,10 +1139,6 @@ error:
     if (!U_FAILURE(*err)) {
         *err = U_ILLEGAL_ARGUMENT_ERROR;
     }
-
-    return -1;
-
-
 }
 
 static UBool
@@ -1229,59 +1169,91 @@ do_canonicalize(const char*    localeID,
 }
 
 U_CAPI int32_t U_EXPORT2
-uloc_addLikelySubtags(const char*    localeID,
-         char* maximizedLocaleID,
-         int32_t maximizedLocaleIDCapacity,
-         UErrorCode* err)
-{
+uloc_addLikelySubtags(const char* localeID,
+                      char* maximizedLocaleID,
+                      int32_t maximizedLocaleIDCapacity,
+                      UErrorCode* status) {
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    icu::CheckedArrayByteSink sink(
+            maximizedLocaleID, maximizedLocaleIDCapacity);
+
+    ulocimp_addLikelySubtags(localeID, sink, status);
+    int32_t reslen = sink.NumberOfBytesAppended();
+
+    if (U_FAILURE(*status)) {
+        return sink.Overflowed() ? reslen : -1;
+    }
+
+    if (sink.Overflowed()) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+    } else {
+        u_terminateChars(
+                maximizedLocaleID, maximizedLocaleIDCapacity, reslen, status);
+    }
+
+    return reslen;
+}
+
+U_CAPI void U_EXPORT2
+ulocimp_addLikelySubtags(const char* localeID,
+                         icu::ByteSink& sink,
+                         UErrorCode* status) {
     char localeBuffer[ULOC_FULLNAME_CAPACITY];
 
-    if (!do_canonicalize(
-        localeID,
-        localeBuffer,
-        sizeof(localeBuffer),
-        err)) {
-        return -1;
+    if (do_canonicalize(localeID, localeBuffer, sizeof localeBuffer, status)) {
+        _uloc_addLikelySubtags(localeBuffer, sink, status);
     }
-    else {
-        return _uloc_addLikelySubtags(
-                    localeBuffer,
-                    maximizedLocaleID,
-                    maximizedLocaleIDCapacity,
-                    err);
-    }    
 }
 
 U_CAPI int32_t U_EXPORT2
-uloc_minimizeSubtags(const char*    localeID,
-         char* minimizedLocaleID,
-         int32_t minimizedLocaleIDCapacity,
-         UErrorCode* err)
-{
+uloc_minimizeSubtags(const char* localeID,
+                     char* minimizedLocaleID,
+                     int32_t minimizedLocaleIDCapacity,
+                     UErrorCode* status) {
+    if (U_FAILURE(*status)) {
+        return 0;
+    }
+
+    icu::CheckedArrayByteSink sink(
+            minimizedLocaleID, minimizedLocaleIDCapacity);
+
+    ulocimp_minimizeSubtags(localeID, sink, status);
+    int32_t reslen = sink.NumberOfBytesAppended();
+
+    if (U_FAILURE(*status)) {
+        return sink.Overflowed() ? reslen : -1;
+    }
+
+    if (sink.Overflowed()) {
+        *status = U_BUFFER_OVERFLOW_ERROR;
+    } else {
+        u_terminateChars(
+                minimizedLocaleID, minimizedLocaleIDCapacity, reslen, status);
+    }
+
+    return reslen;
+}
+
+U_CAPI void U_EXPORT2
+ulocimp_minimizeSubtags(const char* localeID,
+                        icu::ByteSink& sink,
+                        UErrorCode* status) {
     char localeBuffer[ULOC_FULLNAME_CAPACITY];
 
-    if (!do_canonicalize(
-        localeID,
-        localeBuffer,
-        sizeof(localeBuffer),
-        err)) {
-        return -1;
+    if (do_canonicalize(localeID, localeBuffer, sizeof localeBuffer, status)) {
+        _uloc_minimizeSubtags(localeBuffer, sink, status);
     }
-    else {
-        return _uloc_minimizeSubtags(
-                    localeBuffer,
-                    minimizedLocaleID,
-                    minimizedLocaleIDCapacity,
-                    err);
-    }    
 }
 
 // Pairs of (language subtag, + or -) for finding out fast if common languages
 // are LTR (minus) or RTL (plus).
-static const char* LANG_DIR_STRING =
+static const char LANG_DIR_STRING[] =
         "root-en-es-pt-zh-ja-ko-de-fr-it-ar+he+fa+ru-nl-pl-th-tr-";
 
-// Implemented here because this calls uloc_addLikelySubtags().
+// Implemented here because this calls ulocimp_addLikelySubtags().
 U_CAPI UBool U_EXPORT2
 uloc_isRightToLeft(const char *locale) {
     UErrorCode errorCode = U_ZERO_ERROR;
@@ -1294,31 +1266,38 @@ uloc_isRightToLeft(const char *locale) {
         errorCode = U_ZERO_ERROR;
         char lang[8];
         int32_t langLength = uloc_getLanguage(locale, lang, UPRV_LENGTHOF(lang), &errorCode);
-        if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING ||
-                langLength == 0) {
+        if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
             return FALSE;
         }
-        const char* langPtr = uprv_strstr(LANG_DIR_STRING, lang);
-        if (langPtr != NULL) {
-            switch (langPtr[langLength]) {
-            case '-': return FALSE;
-            case '+': return TRUE;
-            default: break;  // partial match of a longer code
+        if (langLength > 0) {
+            const char* langPtr = uprv_strstr(LANG_DIR_STRING, lang);
+            if (langPtr != NULL) {
+                switch (langPtr[langLength]) {
+                case '-': return FALSE;
+                case '+': return TRUE;
+                default: break;  // partial match of a longer code
+                }
             }
         }
         // Otherwise, find the likely script.
         errorCode = U_ZERO_ERROR;
-        char likely[ULOC_FULLNAME_CAPACITY];
-        (void)uloc_addLikelySubtags(locale, likely, UPRV_LENGTHOF(likely), &errorCode);
+        icu::CharString likely;
+        {
+            icu::CharStringByteSink sink(&likely);
+            ulocimp_addLikelySubtags(locale, sink, &errorCode);
+        }
         if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING) {
             return FALSE;
         }
-        scriptLength = uloc_getScript(likely, script, UPRV_LENGTHOF(script), &errorCode);
+        scriptLength = uloc_getScript(likely.data(), script, UPRV_LENGTHOF(script), &errorCode);
         if (U_FAILURE(errorCode) || errorCode == U_STRING_NOT_TERMINATED_WARNING ||
                 scriptLength == 0) {
             return FALSE;
         }
     }
+    if (uprv_strcmp(script,"Aran")==0) {
+        uprv_strcpy(script,"Arab"); // The properties functions do not understand Aran
+    }
     UScriptCode scriptCode = (UScriptCode)u_getPropertyValueEnum(UCHAR_SCRIPT, script);
     return uscript_isRightToLeft(scriptCode);
 }
@@ -1330,6 +1309,8 @@ Locale::isRightToLeft() const {
     return uloc_isRightToLeft(getBaseName());
 }
 
+U_NAMESPACE_END
+
 // The following must at least allow for rg key value (6) plus terminator (1).
 #define ULOC_RG_BUFLEN 8
 
@@ -1362,11 +1343,14 @@ ulocimp_getRegionForSupplementalData(const char *localeID, UBool inferRegion,
             rgLen = 0;
         } else if (rgLen == 0 && inferRegion) {
             // no unicode_region_subtag but inferRegion TRUE, try likely subtags
-            char locBuf[ULOC_FULLNAME_CAPACITY];
             rgStatus = U_ZERO_ERROR;
-            (void)uloc_addLikelySubtags(localeID, locBuf, ULOC_FULLNAME_CAPACITY, &rgStatus);
+            icu::CharString locBuf;
+            {
+                icu::CharStringByteSink sink(&locBuf);
+                ulocimp_addLikelySubtags(localeID, sink, &rgStatus);
+            }
             if (U_SUCCESS(rgStatus)) {
-                rgLen = uloc_getCountry(locBuf, rgBuf, ULOC_RG_BUFLEN, status);
+                rgLen = uloc_getCountry(locBuf.data(), rgBuf, ULOC_RG_BUFLEN, status);
                 if (U_FAILURE(*status)) {
                     rgLen = 0;
                 }
@@ -1379,4 +1363,3 @@ ulocimp_getRegionForSupplementalData(const char *localeID, UBool inferRegion,
     return u_terminateChars(region, regionCapacity, rgLen, status);
 }
 
-U_NAMESPACE_END