]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/common/utext.cpp
ICU-62108.0.1.tar.gz
[apple/icu.git] / icuSources / common / utext.cpp
index e0cc5b76c6982a213d5a884fe882ecca4f8bcd1b..a2c9008abf668d56c9bb29582ae79192a3e8c6ea 100644 (file)
@@ -1,12 +1,14 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
 *
-*   Copyright (C) 2005-2011, International Business Machines
+*   Copyright (C) 2005-2016, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 *
 *******************************************************************************
 *   file name:  utext.cpp
-*   encoding:   US-ASCII
+*   encoding:   UTF-8
 *   tab size:   8 (not used)
 *   indentation:4
 *
@@ -19,6 +21,9 @@
 #include "unicode/unistr.h"
 #include "unicode/chariter.h"
 #include "unicode/utext.h"
+#include "unicode/utf.h"
+#include "unicode/utf8.h"
+#include "unicode/utf16.h"
 #include "ustr_imp.h"
 #include "cmemory.h"
 #include "cstring.h"
@@ -118,13 +123,13 @@ utext_setNativeIndex(UText *ut, int64_t index) {
     // Adjust the index position if it is in the middle of a surrogate pair.
     if (ut->chunkOffset<ut->chunkLength) {
         UChar c= ut->chunkContents[ut->chunkOffset];
-        if (UTF16_IS_TRAIL(c)) {
+        if (U16_IS_TRAIL(c)) {
             if (ut->chunkOffset==0) {
                 ut->pFuncs->access(ut, ut->chunkNativeStart, FALSE);
             }
             if (ut->chunkOffset>0) {
                 UChar lead = ut->chunkContents[ut->chunkOffset-1];
-                if (UTF16_IS_LEAD(lead)) {
+                if (U16_IS_LEAD(lead)) {
                     ut->chunkOffset--;
                 }
             }
@@ -451,355 +456,6 @@ utext_equals(const UText *a, const UText *b) {
     return TRUE;
 }
 
-U_CAPI int32_t U_EXPORT2
-utext_compare(UText *s1, int32_t length1,
-              UText *s2, int32_t length2) {
-    UChar32 c1 = 0, c2 = 0;
-    
-    if(length1<0 && length2<0) {
-        /* strcmp style, go until end of string */
-        for(;;) {
-            c1 = UTEXT_NEXT32(s1);
-            c2 = UTEXT_NEXT32(s2);
-            if(c1 != c2) {
-                break;
-            } else if(c1 == U_SENTINEL) {
-                return 0;
-            }
-        }
-    } else {
-        if(length1 < 0) {
-            length1 = INT32_MIN;
-        } else if (length2 < 0) {
-            length2 = INT32_MIN;
-        }
-        
-        /* memcmp/UnicodeString style, both length-specified */        
-        while((length1 > 0 || length1 == INT32_MIN) && (length2 > 0 || length2 == INT32_MIN)) {
-            c1 = UTEXT_NEXT32(s1);
-            c2 = UTEXT_NEXT32(s2);
-                       
-            if(c1 != c2) {
-                break;
-            } else if(c1 == U_SENTINEL) {
-                return 0;
-            }
-            
-            if (length1 != INT32_MIN) {
-                length1 -= 1;
-            }
-            if (length2 != INT32_MIN) {
-                length2 -= 1;
-            }
-        }
-        
-        if(length1 <= 0 && length1 != INT32_MIN) {
-            if(length2 <= 0) {
-                return 0;
-            } else {
-                return -1;
-            }
-        } else if(length2 <= 0 && length2 != INT32_MIN) {
-            if (length1 <= 0) {
-                return 0;
-            } else {
-                return 1;
-            }
-        }
-    }
-    
-    return (int32_t)c1-(int32_t)c2;
-}
-
-U_CAPI int32_t U_EXPORT2
-utext_compareNativeLimit(UText *s1, int64_t limit1,
-                         UText *s2, int64_t limit2) {
-    UChar32 c1, c2;
-    
-    if(limit1<0 && limit2<0) {
-        /* strcmp style, go until end of string */
-        for(;;) {
-            c1 = UTEXT_NEXT32(s1);
-            c2 = UTEXT_NEXT32(s2);
-            if(c1 != c2) {
-                return (int32_t)c1-(int32_t)c2;
-            } else if(c1 == U_SENTINEL) {
-                return 0;
-            }
-        }
-    } else {
-        /* memcmp/UnicodeString style, both length-specified */   
-        int64_t index1 = (limit1 >= 0 ? UTEXT_GETNATIVEINDEX(s1) : 0);
-        int64_t index2 = (limit2 >= 0 ? UTEXT_GETNATIVEINDEX(s2) : 0);
-        
-        while((limit1 < 0 || index1 < limit1) && (limit2 < 0 || index2 < limit2)) {
-            c1 = UTEXT_NEXT32(s1);
-            c2 = UTEXT_NEXT32(s2);
-            
-            if(c1 != c2) {
-                return (int32_t)c1-(int32_t)c2;
-            } else if(c1 == U_SENTINEL) {
-                return 0;
-            }
-            
-            if (limit1 >= 0) {
-                index1 = UTEXT_GETNATIVEINDEX(s1);
-            }
-            if (limit2 >= 0) {
-                index2 = UTEXT_GETNATIVEINDEX(s2);
-            }
-        }
-        
-        if(limit1 >= 0 && index1 >= limit1) {
-            if(index2 >= limit2) {
-                return 0;
-            } else {
-                return -1;
-            }
-        } else {
-            if(index1 >= limit1) {
-                return 0;
-            } else {
-                return 1;
-            }
-        }
-    }
-}
-
-U_CAPI int32_t U_EXPORT2
-utext_caseCompare(UText *s1, int32_t length1,
-                     UText *s2, int32_t length2,
-                     uint32_t options, UErrorCode *pErrorCode) {
-    const UCaseProps *csp;
-    
-    /* case folding variables */
-    const UChar *p;
-    int32_t length;
-    
-    /* case folding buffers, only use current-level start/limit */
-    UChar fold1[UCASE_MAX_STRING_LENGTH+1], fold2[UCASE_MAX_STRING_LENGTH+1];
-    int32_t foldOffset1, foldOffset2, foldLength1, foldLength2;
-    
-    /* current code points */
-    UChar32 c1, c2;
-    uint8_t cLength1, cLength2;
-
-    /* argument checking */
-    if(U_FAILURE(*pErrorCode)) {
-        return 0;
-    }
-    if(s1==NULL || s2==NULL) {
-        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
-    }
-
-    csp=ucase_getSingleton();
-
-    /* for variable-length strings */
-    if(length1 < 0) {
-        length1 = INT32_MIN;
-    }
-    if (length2 < 0) {
-        length2 = INT32_MIN;
-    }
-    
-    /* initialize */
-    foldOffset1 = foldOffset2 = foldLength1 = foldLength2 = 0;
-    
-    /* comparison loop */
-    while((foldOffset1 < foldLength1 || length1 > 0 || length1 == INT32_MIN) &&
-          (foldOffset2 < foldLength2 || length2 > 0 || length2 == INT32_MIN)) {
-        if(foldOffset1 < foldLength1) {
-            U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
-            cLength1 = 0;
-        } else {
-            c1 = UTEXT_NEXT32(s1);
-            if (c1 != U_SENTINEL) {
-                cLength1 = U16_LENGTH(c1);
-                
-                length = ucase_toFullFolding(csp, c1, &p, options);
-                if(length >= 0) {
-                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
-                        u_memcpy(fold1, p, length);
-                        foldOffset1 = 0;
-                        foldLength1 = length;
-                        U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
-                    } else {
-                        c1 = length;
-                    }
-                }
-            }
-            
-            if(length1 != INT32_MIN) {
-                length1 -= 1;
-            }
-        }
-        
-        if(foldOffset2 < foldLength2) {
-            U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
-            cLength2 = 0;
-        } else {
-            c2 = UTEXT_NEXT32(s2);
-            if (c2 != U_SENTINEL) {
-                cLength2 = U16_LENGTH(c2);
-                
-                length = ucase_toFullFolding(csp, c2, &p, options);
-                if(length >= 0) {
-                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
-                        u_memcpy(fold2, p, length);
-                        foldOffset2 = 0;
-                        foldLength2 = length;
-                        U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
-                    } else {
-                        c2 = length;
-                    }
-                }
-            } else if(c1 == U_SENTINEL) {
-                return 0; // end of both strings at once
-            }
-            
-            if(length2 != INT32_MIN) {
-                length2 -= 1;
-            }
-        }
-        
-        if(c1 != c2) {
-            return (int32_t)c1-(int32_t)c2;
-        }
-    }
-    
-    /* By now at least one of the strings is out of characters */
-    length1 += foldLength1 - foldOffset1;
-    length2 += foldLength2 - foldOffset2;
-    
-    if(length1 <= 0 && length1 != INT32_MIN) {
-        if(length2 <= 0) {
-            return 0;
-        } else {
-            return -1;
-        }
-    } else {
-        if (length1 <= 0) {
-            return 0;
-        } else {
-            return 1;
-        }
-    }
-}
-
-U_CAPI int32_t U_EXPORT2
-utext_caseCompareNativeLimit(UText *s1, int64_t limit1,
-                                UText *s2, int64_t limit2,
-                                uint32_t options, UErrorCode *pErrorCode) {
-    const UCaseProps *csp;
-    
-    /* case folding variables */
-    const UChar *p;
-    int32_t length;
-    
-    /* case folding buffers, only use current-level start/limit */
-    UChar fold1[UCASE_MAX_STRING_LENGTH+1], fold2[UCASE_MAX_STRING_LENGTH+1];
-    int32_t foldOffset1, foldOffset2, foldLength1, foldLength2;
-    
-    /* current code points */
-    UChar32 c1, c2;
-    
-    /* native indexes into s1 and s2 */
-    int64_t index1, index2;
-
-    /* argument checking */
-    if(U_FAILURE(*pErrorCode)) {
-        return 0;
-    }
-    if(s1==NULL || s2==NULL) {
-        *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
-        return 0;
-    }
-
-    csp=ucase_getSingleton();
-
-    /* initialize */
-    index1 = (limit1 >= 0 ? UTEXT_GETNATIVEINDEX(s1) : 0);
-    index2 = (limit2 >= 0 ? UTEXT_GETNATIVEINDEX(s2) : 0);
-
-    foldOffset1 = foldOffset2 = foldLength1 = foldLength2 = 0;
-    
-    /* comparison loop */
-    while((foldOffset1 < foldLength1 || limit1 < 0 || index1 < limit1) &&
-          (foldOffset2 < foldLength2 || limit2 < 0 || index2 < limit2)) {
-        if(foldOffset1 < foldLength1) {
-            U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
-        } else {
-            c1 = UTEXT_NEXT32(s1);
-            if (c1 != U_SENTINEL) {
-                length = ucase_toFullFolding(csp, c1, &p, options);
-                if(length >= 0) {
-                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
-                        u_memcpy(fold1, p, length);
-                        foldOffset1 = 0;
-                        foldLength1 = length;
-                        U16_NEXT_UNSAFE(fold1, foldOffset1, c1);
-                    } else {
-                        c1 = length;
-                    }
-                }
-            }
-            
-            if (limit1 >= 0) {
-                index1 = UTEXT_GETNATIVEINDEX(s1);
-            }
-        }
-        
-        if(foldOffset2 < foldLength2) {
-            U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
-        } else {
-            c2 = UTEXT_NEXT32(s2);
-            if (c2 != U_SENTINEL) {
-                length = ucase_toFullFolding(csp, c2, &p, options);
-                if(length >= 0) {
-                    if(length <= UCASE_MAX_STRING_LENGTH) {   // !!!: Does not correctly handle 0-length folded-case strings
-                        u_memcpy(fold2, p, length);
-                        foldOffset2 = 0;
-                        foldLength2 = length;
-                        U16_NEXT_UNSAFE(fold2, foldOffset2, c2);
-                    } else {
-                        c2 = length;
-                    }
-                }
-            } else if(c1 == U_SENTINEL) {
-                return 0;
-            }
-            
-            if (limit2 >= 0) {
-                index2 = UTEXT_GETNATIVEINDEX(s2);
-            }
-        }
-        
-        if(c1 != c2) {
-            return (int32_t)c1-(int32_t)c2;
-        }
-    }
-    
-    /* By now at least one of the strings is out of characters */
-    index1 -= foldLength1 - foldOffset1;
-    index2 -= foldLength2 - foldOffset2;
-    
-    if(limit1 >= 0 && index1 >= limit1) {
-        if(index2 >= limit2) {
-            return 0;
-        } else {
-            return -1;
-        }
-    } else {
-        if(index1 >= limit1) {
-            return 0;
-        } else {
-            return 1;
-        }
-    }
-}
-
-
 U_CAPI UBool U_EXPORT2
 utext_isWritable(const UText *ut)
 {
@@ -862,8 +518,17 @@ utext_copy(UText *ut,
 
 U_CAPI UText * U_EXPORT2
 utext_clone(UText *dest, const UText *src, UBool deep, UBool readOnly, UErrorCode *status) {
-    UText *result;
-    result = src->pFuncs->clone(dest, src, deep, status);
+    if (U_FAILURE(*status)) {
+        return dest;
+    }
+    UText *result = src->pFuncs->clone(dest, src, deep, status);
+    if (U_FAILURE(*status)) {
+        return result;
+    }
+    if (result == NULL) {
+        *status = U_MEMORY_ALLOCATION_ERROR;
+        return result;
+    }
     if (readOnly) {
         utext_freeze(result);
     }
@@ -1152,6 +817,11 @@ shallowTextClone(UText * dest, const UText * src, UErrorCode * status) {
     adjustPointer(dest, &dest->r, src);
     adjustPointer(dest, (const void **)&dest->chunkContents, src);
 
+    // The newly shallow-cloned UText does _not_ own the underlying storage for the text.
+    // (The source for the clone may or may not have owned the text.)
+
+    dest->providerProperties &= ~I32_FLAG(UTEXT_PROVIDER_OWNS_TEXT);
+
     return dest;
 }
 
@@ -1177,9 +847,11 @@ U_CDECL_END
 //------------------------------------------------------------------------------
 
 // Chunk size.
-//     Must be less than 85, because of byte mapping from UChar indexes to native indexes.
+//     Must be less than 85 (256/3), because of byte mapping from UChar indexes to native indexes.
 //     Worst case is three native bytes to one UChar.  (Supplemenaries are 4 native bytes
 //     to two UChars.)
+//     The longest illegal byte sequence treated as a single error (and converted to U+FFFD)
+//     is a three-byte sequence (truncated four-byte sequence).
 //
 enum { UTF8_TEXT_CHUNK_SIZE=32 };
 
@@ -1362,6 +1034,7 @@ utf8TextAccess(UText *ut, int64_t index, UBool forward) {
             // Requested index is in this buffer.
             u8b = (UTF8Buf *)ut->p;   // the current buffer
             mapIndex = ix - u8b->toUCharsMapStart;
+            U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));
             ut->chunkOffset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
             return TRUE;
 
@@ -1563,15 +1236,11 @@ fillForward:
                 int32_t  cIx      = srcIx;
                 int32_t  dIx      = destIx;
                 int32_t  dIxSaved = destIx;
-                U8_NEXT(s8, srcIx, strLen, c);
+                U8_NEXT_OR_FFFD(s8, srcIx, strLen, c);
                 if (c==0 && nulTerminated) {
                     srcIx--;
                     break;
                 }
-                if (c<0) {
-                    // Illegal UTF-8.  Replace with sub character.
-                    c = 0x0fffd;
-                }
 
                 U16_APPEND_UNSAFE(buf, destIx, c);
                 do {
@@ -1632,6 +1301,10 @@ fillReverse:
         // Can only do this if the incoming index is somewhere in the interior of the string.
         //   If index is at the end, there is no character there to look at.
         if (ix != ut->b) {
+            // Note: this function will only move the index back if it is on a trail byte
+            //       and there is a preceding lead byte and the sequence from the lead 
+            //       through this trail could be part of a valid UTF-8 sequence
+            //       Otherwise the index remains unchanged.
             U8_SET_CP_START(s8, 0, ix);
         }
 
@@ -1645,7 +1318,10 @@ fillReverse:
         UChar   *buf = u8b->buf;
         uint8_t *mapToNative = u8b->mapToNative;
         uint8_t *mapToUChars = u8b->mapToUChars;
-        int32_t  toUCharsMapStart = ix - (UTF8_TEXT_CHUNK_SIZE*3 + 1);
+        int32_t  toUCharsMapStart = ix - sizeof(UTF8Buf::mapToUChars) + 1;
+        // Note that toUCharsMapStart can be negative. Happens when the remaining
+        // text from current position to the beginning is less than the buffer size.
+        // + 1 because mapToUChars must have a slot at the end for the bufNativeLimit entry.
         int32_t  destIx = UTF8_TEXT_CHUNK_SIZE+2;   // Start in the overflow region
                                                     //   at end of buffer to leave room
                                                     //   for a surrogate pair at the
@@ -1672,6 +1348,7 @@ fillReverse:
             if (c<0x80) {
                 // Special case ASCII range for speed.
                 buf[destIx] = (UChar)c;
+                U_ASSERT(toUCharsMapStart <= srcIx);
                 mapToUChars[srcIx - toUCharsMapStart] = (uint8_t)destIx;
                 mapToNative[destIx] = (uint8_t)(srcIx - toUCharsMapStart);
             } else {
@@ -1680,15 +1357,11 @@ fillReverse:
                 int32_t  sIx      = srcIx;  // ix of last byte of multi-byte u8 char
 
                 // Get the full character from the UTF8 string.
-                //   use code derived from tbe macros in utf.8
+                //   use code derived from tbe macros in utf8.h
                 //   Leaves srcIx pointing at the first byte of the UTF-8 char.
                 //
-                if (c<=0xbf) {
-                    c=utf8_prevCharSafeBody(s8, 0, &srcIx, c, -1);
-                    // leaves srcIx at first byte of the multi-byte char.
-                } else {
-                    c=0x0fffd;
-                }
+                c=utf8_prevCharSafeBody(s8, 0, &srcIx, c, -3);
+                // leaves srcIx at first byte of the multi-byte char.
 
                 // Store the character in UTF-16 buffer.
                 if (c<0x10000) {
@@ -1705,6 +1378,7 @@ fillReverse:
                 do {
                     mapToUChars[sIx-- - toUCharsMapStart] = (uint8_t)destIx;
                 } while (sIx >= srcIx);
+                U_ASSERT(toUCharsMapStart <= (srcIx+1));
 
                 // Set native indexing limit to be the current position.
                 //   We are processing a non-ascii, non-native-indexing char now;
@@ -1749,7 +1423,7 @@ utext_strFromUTF8(UChar *dest,
 {
 
     UChar *pDest = dest;
-    UChar *pDestLimit = dest+destCapacity;
+    UChar *pDestLimit = (dest!=NULL)?(dest+destCapacity):NULL;
     UChar32 ch=0;
     int32_t index = 0;
     int32_t reqLength = 0;
@@ -1761,16 +1435,13 @@ utext_strFromUTF8(UChar *dest,
         if(ch <=0x7f){
             *pDest++=(UChar)ch;
         }else{
-            ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -1);
-            if(ch<0){
-                ch = 0xfffd;
-            }
+            ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -3);
             if(U_IS_BMP(ch)){
                 *(pDest++)=(UChar)ch;
             }else{
-                *(pDest++)=UTF16_LEAD(ch);
+                *(pDest++)=U16_LEAD(ch);
                 if(pDest<pDestLimit){
-                    *(pDest++)=UTF16_TRAIL(ch);
+                    *(pDest++)=U16_TRAIL(ch);
                 }else{
                     reqLength++;
                     break;
@@ -1784,10 +1455,7 @@ utext_strFromUTF8(UChar *dest,
         if(ch <= 0x7f){
             reqLength++;
         }else{
-            ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -1);
-            if(ch<0){
-                ch = 0xfffd;
-            }
+            ch=utf8_nextCharSafeBody(pSrc, &index, srcLength, ch, -3);
             reqLength+=U16_LENGTH(ch);
         }
     }
@@ -1885,6 +1553,7 @@ utf8TextMapIndexToUTF16(const UText *ut, int64_t index64) {
     U_ASSERT(index>=ut->chunkNativeStart+ut->nativeIndexingLimit);
     U_ASSERT(index<=ut->chunkNativeLimit);
     int32_t mapIndex = index - u8b->toUCharsMapStart;
+    U_ASSERT(mapIndex < (int32_t)sizeof(UTF8Buf::mapToUChars));
     int32_t offset = u8b->mapToUChars[mapIndex] - u8b->bufStartIdx;
     U_ASSERT(offset>=0 && offset<=ut->chunkLength);
     return offset;
@@ -1935,7 +1604,7 @@ utf8TextClose(UText *ut) {
 U_CDECL_END
 
 
-static const struct UTextFuncs utf8Funcs = 
+static const struct UTextFuncs utf8Funcs =
 {
     sizeof(UTextFuncs),
     0, 0, 0,             // Reserved alignment padding
@@ -2222,7 +1891,7 @@ repTextExtract(UText *ut,
     UnicodeString buffer(dest, 0, destCapacity); // writable alias
     rep->extractBetween(start32, limit32, buffer);
     repTextAccess(ut, limit32, TRUE);
-    
+
     return u_terminateUChars(dest, destCapacity, length, status);
 }
 
@@ -2344,7 +2013,7 @@ repTextCopy(UText *ut,
     repTextAccess(ut, nativeIterIndex, TRUE);
 }
 
-static const struct UTextFuncs repFuncs = 
+static const struct UTextFuncs repFuncs =
 {
     sizeof(UTextFuncs),
     0, 0, 0,           // Reserved alignment padding
@@ -2352,8 +2021,8 @@ static const struct UTextFuncs repFuncs =
     repTextLength,
     repTextAccess,
     repTextExtract,
-    repTextReplace,   
-    repTextCopy,   
+    repTextReplace,
+    repTextCopy,
     NULL,              // MapOffsetToNative,
     NULL,              // MapIndexToUTF16,
     repTextClose,
@@ -2374,6 +2043,9 @@ utext_openReplaceable(UText *ut, Replaceable *rep, UErrorCode *status)
         return NULL;
     }
     ut = utext_setup(ut, sizeof(ReplExtra), status);
+    if(U_FAILURE(*status)) {
+        return ut;
+    }
 
     ut->providerProperties = I32_FLAG(UTEXT_PROVIDER_WRITABLE);
     if(rep->hasMetaData()) {
@@ -2566,13 +2238,13 @@ unistrTextCopy(UText *ut,
     }
 
     if(move) {
-        // move: copy to destIndex, then replace original with nothing
+        // move: copy to destIndex, then remove original
         int32_t segLength=limit32-start32;
         us->copy(start32, limit32, destIndex32);
         if(destIndex32<start32) {
             start32+=segLength;
         }
-        us->replace(start32, segLength, NULL, 0);
+        us->remove(start32, segLength);
     } else {
         // copy
         us->copy(start32, limit32, destIndex32);
@@ -2595,7 +2267,7 @@ unistrTextCopy(UText *ut,
 
 }
 
-static const struct UTextFuncs unistrFuncs = 
+static const struct UTextFuncs unistrFuncs =
 {
     sizeof(UTextFuncs),
     0, 0, 0,             // Reserved alignment padding
@@ -2603,8 +2275,8 @@ static const struct UTextFuncs unistrFuncs =
     unistrTextLength,
     unistrTextAccess,
     unistrTextExtract,
-    unistrTextReplace,   
-    unistrTextCopy,   
+    unistrTextReplace,
+    unistrTextCopy,
     NULL,                // MapOffsetToNative,
     NULL,                // MapIndexToUTF16,
     unistrTextClose,
@@ -2620,20 +2292,9 @@ U_CDECL_END
 
 U_CAPI UText * U_EXPORT2
 utext_openUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) {
-    // TODO:  use openConstUnicodeString, then add in the differences.
-    //
-    ut = utext_setup(ut, 0, status);
+    ut = utext_openConstUnicodeString(ut, s, status);
     if (U_SUCCESS(*status)) {
-        ut->pFuncs              = &unistrFuncs;
-        ut->context             = s;
-        ut->providerProperties  = I32_FLAG(UTEXT_PROVIDER_STABLE_CHUNKS)|
-                                  I32_FLAG(UTEXT_PROVIDER_WRITABLE);
-
-        ut->chunkContents       = s->getBuffer();
-        ut->chunkLength         = s->length();
-        ut->chunkNativeStart    = 0;
-        ut->chunkNativeLimit    = ut->chunkLength;
-        ut->nativeIndexingLimit = ut->chunkLength;
+        ut->providerProperties |= I32_FLAG(UTEXT_PROVIDER_WRITABLE);
     }
     return ut;
 }
@@ -2642,6 +2303,13 @@ utext_openUnicodeString(UText *ut, UnicodeString *s, UErrorCode *status) {
 
 U_CAPI UText * U_EXPORT2
 utext_openConstUnicodeString(UText *ut, const UnicodeString *s, UErrorCode *status) {
+    if (U_SUCCESS(*status) && s->isBogus()) {
+        // The UnicodeString is bogus, but we still need to detach the UText
+        //   from whatever it was hooked to before, if anything.
+        utext_openUChars(ut, NULL, 0, status);
+        *status = U_ILLEGAL_ARGUMENT_ERROR;
+        return ut;
+    }
     ut = utext_setup(ut, 0, status);
     //    note:  use the standard (writable) function table for UnicodeString.
     //           The flag settings disable writing, so having the functions in
@@ -2865,7 +2533,6 @@ ucstrTextExtract(UText *ut,
     } else {
         limit32 = pinIndex(limit, INT32_MAX);
     }
-
     di = 0;
     for (si=start32; si<limit32; si++) {
         if (strLength<0 && s[si]==0) {
@@ -2875,8 +2542,10 @@ ucstrTextExtract(UText *ut,
             ut->chunkLength         = si;
             ut->nativeIndexingLimit = si;
             strLength               = si;
+            limit32                 = si;
             break;
         }
+        U_ASSERT(di>=0); /* to ensure di never exceeds INT32_MAX, which must not happen logically */
         if (di<destCapacity) {
             // only store if there is space.
             dest[di] = s[si];
@@ -2895,16 +2564,21 @@ ucstrTextExtract(UText *ut,
     // If the limit index points to a lead surrogate of a pair,
     //   add the corresponding trail surrogate to the destination.
     if (si>0 && U16_IS_LEAD(s[si-1]) &&
-        ((si<strLength || strLength<0)  && U16_IS_TRAIL(s[si])))
+            ((si<strLength || strLength<0)  && U16_IS_TRAIL(s[si])))
     {
         if (di<destCapacity) {
             // store only if there is space in the output buffer.
-            dest[di++] = s[si++];
+            dest[di++] = s[si];
         }
+        si++;
     }
 
     // Put iteration position at the point just following the extracted text
-    ut->chunkOffset = uprv_min(strLength, start32 + destCapacity);
+    if (si <= ut->chunkNativeLimit) {
+        ut->chunkOffset = si;
+    } else {
+        ucstrTextAccess(ut, si, TRUE);
+    }
 
     // Add a terminating NUL if space in the buffer permits,
     // and set the error status as required.
@@ -2912,7 +2586,7 @@ ucstrTextExtract(UText *ut,
     return di;
 }
 
-static const struct UTextFuncs ucstrFuncs = 
+static const struct UTextFuncs ucstrFuncs =
 {
     sizeof(UTextFuncs),
     0, 0, 0,           // Reserved alignment padding
@@ -3083,6 +2757,9 @@ charIterTextClone(UText *dest, const UText *src, UBool deep, UErrorCode * status
         CharacterIterator *srcCI =(CharacterIterator *)src->context;
         srcCI = srcCI->clone();
         dest = utext_openCharacterIterator(dest, srcCI, status);
+        if (U_FAILURE(*status)) {
+            return dest;
+        }
         // cast off const on getNativeIndex.
         //   For CharacterIterator based UTexts, this is safe, the operation is const.
         int64_t  ix = utext_getNativeIndex((UText *)src);
@@ -3119,6 +2796,7 @@ charIterTextExtract(UText *ut,
     while (srci<limit32) {
         UChar32 c = ci->next32PostInc();
         int32_t  len = U16_LENGTH(c);
+        U_ASSERT(desti+len>0); /* to ensure desti+len never exceeds MAX_INT32, which must not happen logically */
         if (desti+len <= destCapacity) {
             U16_APPEND_UNSAFE(dest, desti, c);
             copyLimit = srci+len;
@@ -3128,14 +2806,14 @@ charIterTextExtract(UText *ut,
         }
         srci += len;
     }
-    
+
     charIterTextAccess(ut, copyLimit, TRUE);
 
     u_terminateUChars(dest, destCapacity, desti, status);
     return desti;
 }
 
-static const struct UTextFuncs charIterFuncs = 
+static const struct UTextFuncs charIterFuncs =
 {
     sizeof(UTextFuncs),
     0, 0, 0,             // Reserved alignment padding
@@ -3195,6 +2873,3 @@ utext_openCharacterIterator(UText *ut, CharacterIterator *ci, UErrorCode *status
     }
     return ut;
 }
-
-
-