ICU-511.25.tar.gz
[apple/icu.git] / icuSources / i18n / regexcmp.cpp
index dd4370c00c01f8eb449e5dc57eb1685084536d9e..b17ef53c93d73df4603bf422b1a619a0c085c5b8 100644 (file)
@@ -1,8 +1,7 @@
-
 //
 //  file:  regexcmp.cpp
 //
-//  Copyright (C) 2002-2008 International Business Machines Corporation and others.
+//  Copyright (C) 2002-2012 International Business Machines Corporation and others.
 //  All Rights Reserved.
 //
 //  This file contains the ICU regular expression compiler, which is responsible
@@ -14,6 +13,7 @@
 
 #if !UCONFIG_NO_REGULAR_EXPRESSIONS
 
+#include "unicode/ustring.h"
 #include "unicode/unistr.h"
 #include "unicode/uniset.h"
 #include "unicode/uchar.h"
 #include "unicode/parsepos.h"
 #include "unicode/parseerr.h"
 #include "unicode/regex.h"
-#include "util.h"
+#include "unicode/utf.h"
+#include "unicode/utf16.h"
+#include "patternprops.h"
+#include "putilimp.h"
 #include "cmemory.h"
 #include "cstring.h"
 #include "uvectr32.h"
+#include "uvectr64.h"
 #include "uassert.h"
 #include "ucln_in.h"
 #include "uinvchar.h"
@@ -34,6 +38,7 @@
                         //   generated by a Perl script.
 #include "regexcmp.h"
 #include "regexst.h"
+#include "regextxt.h"
 
 
 
@@ -48,11 +53,14 @@ U_NAMESPACE_BEGIN
 RegexCompile::RegexCompile(RegexPattern *rxp, UErrorCode &status) :
    fParenStack(status), fSetStack(status), fSetOpStack(status)
 {
+    // Lazy init of all shared global sets (needed for init()'s empty text)
+    RegexStaticSets::initGlobals(&status);
+
     fStatus           = &status;
 
     fRXPat            = rxp;
     fScanIndex        = 0;
-    fNextIndex        = 0;
+    fLastChar         = -1;
     fPeekChar         = -1;
     fLineNum          = 1;
     fCharNum          = 0;
@@ -63,7 +71,6 @@ RegexCompile::RegexCompile(RegexPattern *rxp, UErrorCode &status) :
 
     fMatchOpenParen   = -1;
     fMatchCloseParen  = -1;
-    fStringOpStart    = -1;
 
     if (U_SUCCESS(status) && U_FAILURE(rxp->fDeferredStatus)) {
         status = rxp->fDeferredStatus;
@@ -98,6 +105,25 @@ void    RegexCompile::compile(
                          const UnicodeString &pat,   // Source pat to be compiled.
                          UParseError &pp,            // Error position info
                          UErrorCode &e)              // Error Code
+{
+    fRXPat->fPatternString = new UnicodeString(pat);
+    UText patternText = UTEXT_INITIALIZER;
+    utext_openConstUnicodeString(&patternText, fRXPat->fPatternString, &e);
+    
+    if (U_SUCCESS(e)) {
+        compile(&patternText, pp, e);
+        utext_close(&patternText);
+    }
+}
+
+//
+//   compile, UText mode
+//     All the work is actually done here.
+//
+void    RegexCompile::compile(
+                         UText *pat,                 // Source pat to be compiled.
+                         UParseError &pp,            // Error position info
+                         UErrorCode &e)              // Error Code
 {
     fStatus             = &e;
     fParseErr           = &pp;
@@ -109,18 +135,24 @@ void    RegexCompile::compile(
     }
 
     // There should be no pattern stuff in the RegexPattern object.  They can not be reused.
-    U_ASSERT(fRXPat->fPattern.length() == 0);
+    U_ASSERT(fRXPat->fPattern == NULL || utext_nativeLength(fRXPat->fPattern) == 0);
 
     // Prepare the RegexPattern object to receive the compiled pattern.
-    fRXPat->fPattern        = pat;
+    fRXPat->fPattern        = utext_clone(fRXPat->fPattern, pat, FALSE, TRUE, fStatus);
     fRXPat->fStaticSets     = RegexStaticSets::gStaticSets->fPropSets;
     fRXPat->fStaticSets8    = RegexStaticSets::gStaticSets->fPropSets8;
 
 
     // Initialize the pattern scanning state machine
-    fPatternLength = pat.length();
+    fPatternLength = utext_nativeLength(pat);
     uint16_t                state = 1;
     const RegexTableEl      *tableEl;
+
+    // UREGEX_LITERAL force entire pattern to be treated as a literal string.
+    if (fModeFlags & UREGEX_LITERAL) {
+        fQuoteMode = TRUE;
+    }
+
     nextChar(fC);                        // Fetch the first char from the pattern string.
 
     //
@@ -177,6 +209,7 @@ void    RegexCompile::compile(
             if (tableEl->fCharClass >= 128 && tableEl->fCharClass < 240 &&   // Table specs a char class &&
                 fC.fQuoted == FALSE &&                                       //   char is not escaped &&
                 fC.fChar != (UChar32)-1) {                                   //   char is not EOF
+                U_ASSERT(tableEl->fCharClass <= 137);
                 if (RegexStaticSets::gStaticSets->fRuleSets[tableEl->fCharClass-128].contains(fC.fChar)) {
                     // Table row specified a character class, or set of characters,
                     //   and the current char matches it.
@@ -251,34 +284,13 @@ void    RegexCompile::compile(
     // The pattern has now been read and processed, and the compiled code generated.
     //
 
-    // Back-reference fixup
-    //
-    int32_t loc;
-    for (loc=0; loc<fRXPat->fCompiledPat->size(); loc++) {
-        int32_t op = fRXPat->fCompiledPat->elementAti(loc);
-        int32_t opType = URX_TYPE(op);
-        if (opType == URX_BACKREF || opType == URX_BACKREF_I) {
-            int32_t where = URX_VAL(op);
-            if (where > fRXPat->fGroupMap->size()) {
-                error(U_REGEX_INVALID_BACK_REF);
-                break;
-            }
-            where = fRXPat->fGroupMap->elementAti(where-1);
-            op    = URX_BUILD(opType, where);
-            fRXPat->fCompiledPat->setElementAt(op, loc);
-        }
-    }
-
-
     //
     // Compute the number of digits requried for the largest capture group number.
     //
     fRXPat->fMaxCaptureDigits = 1;
     int32_t  n = 10;
-    for (;;) {
-        if (n > fRXPat->fGroupMap->size()) {
-            break;
-        }
+    int32_t  groupCount = fRXPat->fGroupMap->size();
+    while (n <= groupCount) {
         fRXPat->fMaxCaptureDigits++;
         n *= 10;
     }
@@ -287,10 +299,15 @@ void    RegexCompile::compile(
     // The pattern's fFrameSize so far has accumulated the requirements for
     //   storage for capture parentheses, counters, etc. that are encountered
     //   in the pattern.  Add space for the two variables that are always
-    //   present in the saved state:  the input string position and the
-    //   position in the compiled pattern.
+    //   present in the saved state:  the input string position (int64_t) and
+    //   the position in the compiled pattern.
     //
-    fRXPat->fFrameSize+=2;
+    fRXPat->fFrameSize+=RESTACKFRAME_HDRCOUNT;
+
+    //
+    // Optimization pass 1: NOPs, back-references, and case-folding
+    //
+    stripNOPs();
 
     //
     // Get bounds for the minimum and maximum length of a string that this
@@ -300,10 +317,9 @@ void    RegexCompile::compile(
     fRXPat->fMinMatchLen = minMatchLength(3, fRXPat->fCompiledPat->size()-1);
 
     //
-    // Optimization passes
+    // Optimization pass 2: match start type
     //
     matchStartType();
-    stripNOPs();
 
     //
     // Set up fast latin-1 range sets
@@ -388,13 +404,16 @@ UBool RegexCompile::doParseActions(int32_t action)
     case doOrOperator:
         // Scanning a '|', as in (A|B)
         {
+            // Generate code for any pending literals preceding the '|'
+            fixLiterals(FALSE);
+
             // Insert a SAVE operation at the start of the pattern section preceding
             //   this OR at this level.  This SAVE will branch the match forward
             //   to the right hand side of the OR in the event that the left hand
             //   side fails to match and backtracks.  Locate the position for the
             //   save from the location on the top of the parentheses stack.
             int32_t savePosition = fParenStack.popi();
-            int32_t op = fRXPat->fCompiledPat->elementAti(savePosition);
+            int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(savePosition);
             U_ASSERT(URX_TYPE(op) == URX_NOP);  // original contents of reserved location
             op = URX_BUILD(URX_STATE_SAVE, fRXPat->fCompiledPat->size()+1);
             fRXPat->fCompiledPat->setElementAt(op, savePosition);
@@ -428,15 +447,16 @@ UBool RegexCompile::doParseActions(int32_t action)
         //             is an '|' alternation within the parens.
         //
         //    Each capture group gets three slots in the save stack frame:
-        //         0:   Capture Group start position (in input string being matched.)
-        //         1:   Capture Group end   positino.
-        //         2:   Start of Match-in-progress.
+        //         0: Capture Group start position (in input string being matched.)
+        //         1: Capture Group end position.
+        //         2: Start of Match-in-progress.
         //    The first two locations are for a completed capture group, and are
         //     referred to by back references and the like.
         //    The third location stores the capture start position when an START_CAPTURE is
         //      encountered.  This will be promoted to a completed capture when (and if) the corresponding
-        //      END_CAPure is encountered.
+        //      END_CAPTURE is encountered.
         {
+            fixLiterals();
             fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
             int32_t  varsLoc    = fRXPat->fFrameSize;    // Reserve three slots in match stack frame.
             fRXPat->fFrameSize += 3;
@@ -466,6 +486,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         //      - NOP, which may later be replaced by a save-state if there
         //             is an '|' alternation within the parens.
         {
+            fixLiterals();
             fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
             fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
 
@@ -488,6 +509,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         //      - NOP, which may later be replaced by a save-state if there
         //             is an '|' alternation within the parens.
         {
+            fixLiterals();
             fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
             int32_t  varLoc    = fRXPat->fDataSize;    // Reserve a data location for saving the
             fRXPat->fDataSize += 1;                    //  state stack ptr.
@@ -535,6 +557,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         //
         //  Two data slots are reserved, for saving the stack ptr and the input position.
         {
+            fixLiterals();
             int32_t dataLoc = fRXPat->fDataSize;
             fRXPat->fDataSize += 2;
             int32_t op = URX_BUILD(URX_LA_START, dataLoc);
@@ -578,6 +601,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         //    7.    END_LA                // Restore match region, in case look-ahead was using
         //                                        an alternate (transparent) region.
         {
+            fixLiterals();
             int32_t dataLoc = fRXPat->fDataSize;
             fRXPat->fDataSize += 2;
             int32_t op = URX_BUILD(URX_LA_START, dataLoc);
@@ -596,7 +620,7 @@ UBool RegexCompile::doParseActions(int32_t action)
             fParenStack.push(fRXPat->fCompiledPat->size()-2, *fStatus);   // The STATE_SAVE location
             fParenStack.push(fRXPat->fCompiledPat->size()-1, *fStatus);   // The second NOP location
 
-            // Instructions #5 and #6 will be added when the ')' is encountered.
+            // Instructions #5 - #7 will be added when the ')' is encountered.
         }
         break;
 
@@ -621,6 +645,9 @@ UBool RegexCompile::doParseActions(int32_t action)
             //              2:    Start index of match current match attempt.
             //              3:    Original Input String len.
 
+            // Generate match code for any pending literals.
+            fixLiterals();
+
             // Allocate data space
             int32_t dataLoc = fRXPat->fDataSize;
             fRXPat->fDataSize += 4;
@@ -674,6 +701,9 @@ UBool RegexCompile::doParseActions(int32_t action)
             //              2:    Start index of match current match attempt.
             //              3:    Original Input String len.
 
+            // Generate match code for any pending literals.
+            fixLiterals();
+
             // Allocate data space
             int32_t dataLoc = fRXPat->fDataSize;
             fRXPat->fDataSize += 4;
@@ -758,7 +788,7 @@ UBool RegexCompile::doParseActions(int32_t action)
 
             // Check for simple constructs, which may get special optimized code.
             if (topLoc == fRXPat->fCompiledPat->size() - 1) {
-                int32_t repeatedOp = fRXPat->fCompiledPat->elementAti(topLoc);
+                int32_t repeatedOp = (int32_t)fRXPat->fCompiledPat->elementAti(topLoc);
 
                 if (URX_TYPE(repeatedOp) == URX_SETREF) {
                     // Emit optimized code for [char set]+
@@ -901,7 +931,7 @@ UBool RegexCompile::doParseActions(int32_t action)
             // Check for simple *, where the construct being repeated
             //   compiled to single opcode, and might be optimizable.
             if (topLoc == fRXPat->fCompiledPat->size() - 1) {
-                int32_t repeatedOp = fRXPat->fCompiledPat->elementAti(topLoc);
+                int32_t repeatedOp = (int32_t)fRXPat->fCompiledPat->elementAti(topLoc);
 
                 if (URX_TYPE(repeatedOp) == URX_SETREF) {
                     // Emit optimized code for a [char set]*
@@ -1053,7 +1083,7 @@ UBool RegexCompile::doParseActions(int32_t action)
             int32_t  op        = URX_BUILD(URX_STO_SP, varLoc);
             fRXPat->fCompiledPat->setElementAt(op, topLoc);
 
-            int32_t loopOp = fRXPat->fCompiledPat->popi();
+            int32_t loopOp = (int32_t)fRXPat->fCompiledPat->popi();
             U_ASSERT(URX_TYPE(loopOp) == URX_CTR_LOOP && URX_VAL(loopOp) == topLoc);
             loopOp++;     // point LoopOp after the just-inserted STO_SP
             fRXPat->fCompiledPat->push(loopOp, *fStatus);
@@ -1095,6 +1125,7 @@ UBool RegexCompile::doParseActions(int32_t action)
     case doDotAny:
         // scanned a ".",  match any single character.
         {
+            fixLiterals(FALSE);
             int32_t   op;
             if (fModeFlags & UREGEX_DOTALL) {
                 op = URX_BUILD(URX_DOTANY_ALL, 0);
@@ -1109,6 +1140,7 @@ UBool RegexCompile::doParseActions(int32_t action)
 
     case doCaret:
         {
+            fixLiterals(FALSE);
             int32_t op = 0;
             if (       (fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
                 op = URX_CARET;
@@ -1125,6 +1157,7 @@ UBool RegexCompile::doParseActions(int32_t action)
 
     case doDollar:
         {
+            fixLiterals(FALSE);
             int32_t op = 0;
             if (       (fModeFlags & UREGEX_MULTILINE) == 0 && (fModeFlags & UREGEX_UNIX_LINES) == 0) {
                 op = URX_DOLLAR;
@@ -1140,6 +1173,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         break;
 
     case doBackslashA:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_CARET, 0), *fStatus);
         break;
 
@@ -1150,6 +1184,7 @@ UBool RegexCompile::doParseActions(int32_t action)
                 error(U_UNSUPPORTED_ERROR);
             }
             #endif
+            fixLiterals(FALSE);
             int32_t op = (fModeFlags & UREGEX_UWORD)? URX_BACKSLASH_BU : URX_BACKSLASH_B;
             fRXPat->fCompiledPat->addElement(URX_BUILD(op, 1), *fStatus);
         }
@@ -1162,53 +1197,64 @@ UBool RegexCompile::doParseActions(int32_t action)
                 error(U_UNSUPPORTED_ERROR);
             }
             #endif
+            fixLiterals(FALSE);
             int32_t op = (fModeFlags & UREGEX_UWORD)? URX_BACKSLASH_BU : URX_BACKSLASH_B;
             fRXPat->fCompiledPat->addElement(URX_BUILD(op, 0), *fStatus);
         }
         break;
 
     case doBackslashD:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_D, 1), *fStatus);
         break;
 
     case doBackslashd:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_D, 0), *fStatus);
         break;
 
     case doBackslashG:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_G, 0), *fStatus);
         break;
 
     case doBackslashS:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(
             URX_BUILD(URX_STAT_SETREF_N, URX_ISSPACE_SET), *fStatus);
         break;
 
     case doBackslashs:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(
             URX_BUILD(URX_STATIC_SETREF, URX_ISSPACE_SET), *fStatus);
         break;
 
     case doBackslashW:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(
             URX_BUILD(URX_STAT_SETREF_N, URX_ISWORD_SET), *fStatus);
         break;
 
     case doBackslashw:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(
             URX_BUILD(URX_STATIC_SETREF, URX_ISWORD_SET), *fStatus);
         break;
 
     case doBackslashX:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_X, 0), *fStatus);
         break;
 
 
     case doBackslashZ:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_DOLLAR, 0), *fStatus);
         break;
 
     case doBackslashz:
+        fixLiterals(FALSE);
         fRXPat->fCompiledPat->addElement(URX_BUILD(URX_BACKSLASH_Z, 0), *fStatus);
         break;
 
@@ -1217,11 +1263,13 @@ UBool RegexCompile::doParseActions(int32_t action)
         break;
 
     case doExit:
+        fixLiterals(FALSE);
         returnVal = FALSE;
         break;
 
     case doProperty:
         {
+            fixLiterals(FALSE);
             UnicodeSet *theSet = scanProp();
             compileSet(theSet);
         }
@@ -1264,7 +1312,9 @@ UBool RegexCompile::doParseActions(int32_t action)
             // Because capture groups can be forward-referenced by back-references,
             //  we fill the operand with the capture group number.  At the end
             //  of compilation, it will be changed to the variable's location.
-            U_ASSERT(groupNum > 0);
+            U_ASSERT(groupNum > 0);  // Shouldn't happen.  '\0' begins an octal escape sequence,
+                                     //    and shouldn't enter this code path at all.
+            fixLiterals(FALSE);
             int32_t  op;
             if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
                 op = URX_BUILD(URX_BACKREF_I, groupNum);
@@ -1409,14 +1459,14 @@ UBool RegexCompile::doParseActions(int32_t action)
         break;
 
     case doSetMatchMode:
+        // Emit code to match any pending literals, using the not-yet changed match mode.
+        fixLiterals();
+
         // We've got a (?i) or similar.  The match mode is being changed, but
         //   the change is not scoped to a parenthesized block.
         U_ASSERT(fNewModeFlags < 0);
         fModeFlags = fNewModeFlags;
 
-        // Prevent any string from spanning across the change of match mode.
-        //   Otherwise the pattern "abc(?i)def" would make a single string of "abcdef"
-        fixLiterals();
         break;
 
 
@@ -1430,6 +1480,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         //      - NOP, which may later be replaced by a save-state if there
         //             is an '|' alternation within the parens.
         {
+            fixLiterals(FALSE);
             fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
             fRXPat->fCompiledPat->addElement(URX_BUILD(URX_NOP, 0), *fStatus);
 
@@ -1525,6 +1576,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         }
 
     case doSetBegin:
+        fixLiterals(FALSE);
         fSetStack.push(new UnicodeSet(), *fStatus);
         fSetOpStack.push(setStart, *fStatus);
         if ((fModeFlags & UREGEX_CASE_INSENSITIVE) != 0) {
@@ -1574,12 +1626,10 @@ UBool RegexCompile::doParseActions(int32_t action)
         // Have encountered the ']' that closes a set.
         //    Force the evaluation of any pending operations within this set,
         //    leave the completed set on the top of the set stack.
-        {
         setEval(setEnd);
-        int32_t setOp = fSetOpStack.popi();
-        U_ASSERT(setOp==setStart);
+        U_ASSERT(fSetOpStack.peeki()==setStart);
+        fSetOpStack.popi();
         break;
-      }
 
     case doSetFinish:
         {
@@ -1661,7 +1711,7 @@ UBool RegexCompile::doParseActions(int32_t action)
         }
 
 
-        case  doSetNegate:
+    case  doSetNegate:
         // Scanned a '^' at the start of a set.
         // Push the negation operator onto the set op stack.
         // A twist for case-insensitive matching:
@@ -1728,7 +1778,6 @@ UBool RegexCompile::doParseActions(int32_t action)
         break;
         }
 
-
     default:
         U_ASSERT(FALSE);
         error(U_REGEX_INTERNAL_ERROR);
@@ -1750,111 +1799,18 @@ UBool RegexCompile::doParseActions(int32_t action)
 //                             or an escape sequence that reduces to a character.
 //                         Add it to the string containing all literal chars/strings from
 //                             the pattern.
-//                         If we are in a pattern string already, add the new char to it.
-//                         If we aren't in a pattern string, begin one now.
 //
 //------------------------------------------------------------------------------
 void RegexCompile::literalChar(UChar32 c)  {
-    int32_t           op;            // An operation in the compiled pattern.
-    int32_t           opType;
-    int32_t           patternLoc;   // A position in the compiled pattern.
-    int32_t           stringLen;
-
-
-    // If the last thing compiled into the pattern was not a literal char,
-    //   force this new literal char to begin a new string, and not append to the previous.
-    op     = fRXPat->fCompiledPat->lastElementi();
-    opType = URX_TYPE(op);
-    if (!(opType == URX_STRING_LEN || opType == URX_ONECHAR || opType == URX_ONECHAR_I)) {
-        fixLiterals();
-    }
-
-    if (fStringOpStart == -1) {
-        // First char of a string in the pattern.
-        // Emit a OneChar op into the compiled pattern.
-        emitONE_CHAR(c);
-
-        // Also add it to the string pool, in case we get a second adjacent literal
-        //   and want to change form ONE_CHAR to STRING
-        fStringOpStart = fRXPat->fLiteralText.length();
-        fRXPat->fLiteralText.append(c);
-        return;
-    }
-
-    // We are adding onto an existing string
-    fRXPat->fLiteralText.append(c);
-
-    op     = fRXPat->fCompiledPat->lastElementi();
-    opType = URX_TYPE(op);
-    U_ASSERT(opType == URX_ONECHAR || opType == URX_ONECHAR_I || opType == URX_STRING_LEN);
-
-    // If the most recently emitted op is a URX_ONECHAR,
-    if (opType == URX_ONECHAR || opType == URX_ONECHAR_I) {
-        if (U16_IS_TRAIL(c) && U16_IS_LEAD(URX_VAL(op))) {
-            // The most recently emitted op is a ONECHAR that was the first half
-            //   of a surrogate pair.  Update the ONECHAR's operand to be the
-            //   supplementary code point resulting from both halves of the pair.
-            c = U16_GET_SUPPLEMENTARY(URX_VAL(op), c);
-            op = URX_BUILD(opType, c);
-            patternLoc = fRXPat->fCompiledPat->size() - 1;
-            fRXPat->fCompiledPat->setElementAt(op, patternLoc);
-            return;
-        }
-
-        // The most recently emitted op is a ONECHAR.
-        //  We've now received another adjacent char.  Change the ONECHAR op
-        //   to a string op.
-        if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
-            op     = URX_BUILD(URX_STRING_I, fStringOpStart);
-        } else {
-            op     = URX_BUILD(URX_STRING, fStringOpStart);
-        }
-        patternLoc = fRXPat->fCompiledPat->size() - 1;
-        fRXPat->fCompiledPat->setElementAt(op, patternLoc);
-        op         = URX_BUILD(URX_STRING_LEN, 0);
-        fRXPat->fCompiledPat->addElement(op, *fStatus);
-    }
-
-    // The pattern contains a URX_SRING / URX_STRING_LEN.  Update the
-    //  string length to reflect the new char we just added to the string.
-    stringLen  = fRXPat->fLiteralText.length() - fStringOpStart;
-    op         = URX_BUILD(URX_STRING_LEN, stringLen);
-    patternLoc = fRXPat->fCompiledPat->size() - 1;
-    fRXPat->fCompiledPat->setElementAt(op, patternLoc);
-}
-
-
-
-//------------------------------------------------------------------------------
-//
-//    emitONE_CHAR         emit a ONE_CHAR op into the generated code.
-//                         Choose cased or uncased version, depending on the
-//                         match mode and whether the character itself is cased.
-//
-//------------------------------------------------------------------------------
-void RegexCompile::emitONE_CHAR(UChar32  c) {
-    int32_t op;
-    if ((fModeFlags & UREGEX_CASE_INSENSITIVE) &&
-        u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
-        // We have a cased character, and are in case insensitive matching mode.
-        c  = u_foldCase(c, U_FOLD_CASE_DEFAULT);
-        op = URX_BUILD(URX_ONECHAR_I, c);
-    } else {
-        // Uncased char, or case sensitive match mode.
-        //  Either way, just generate a literal compare of the char.
-        op = URX_BUILD(URX_ONECHAR, c);
-    }
-    fRXPat->fCompiledPat->addElement(op, *fStatus);
+    fLiteralChars.append(c);
 }
 
 
 //------------------------------------------------------------------------------
 //
 //    fixLiterals           When compiling something that can follow a literal
-//                          string in a pattern, we need to "fix" any preceding
-//                          string, which will cause any subsequent literals to
-//                          begin a new string, rather than appending to the
-//                          old one.
+//                          string in a pattern, emit the code to match the
+//                          accumulated literal string.
 //
 //                          Optionally, split the last char of the string off into
 //                          a single "ONE_CHAR" operation, so that quantifiers can
@@ -1863,63 +1819,68 @@ void RegexCompile::emitONE_CHAR(UChar32  c) {
 //
 //------------------------------------------------------------------------------
 void    RegexCompile::fixLiterals(UBool split) {
-    int32_t  stringStart = fStringOpStart;    // start index of the current literal string
-    int32_t  op;                              // An op from/for the compiled pattern.
-    int32_t  opType;                          // An opcode type from the compiled pattern.
-    int32_t  stringLastCharIdx;
-    UChar32  lastChar;
-    int32_t  stringNextToLastCharIdx;
-    UChar32  nextToLastChar;
-    int32_t  stringLen;
-
-    fStringOpStart = -1;
-    if (!split) {
+    int32_t  op = 0;                       // An op from/for the compiled pattern.
+
+    // If no literal characters have been scanned but not yet had code generated
+    //   for them, nothing needs to be done.
+    if (fLiteralChars.length() == 0) {
         return;
     }
 
-    // Split:  We need to  ensure that the last item in the compiled pattern does
-    //   not refer to a literal string of more than one char.  If it does,
-    //   separate the last char from the rest of the string.
+    int32_t indexOfLastCodePoint = fLiteralChars.moveIndex32(fLiteralChars.length(), -1);
+    UChar32 lastCodePoint = fLiteralChars.char32At(indexOfLastCodePoint);
+
+    // Split:  We need to  ensure that the last item in the compiled pattern 
+    //     refers only to the last literal scanned in the pattern, so that
+    //     quantifiers (*, +, etc.) affect only it, and not a longer string.
+    //     Split before case folding for case insensitive matches.
 
-    // If the last operation from the compiled pattern is not a string,
-    //   nothing needs to be done
-    op     = fRXPat->fCompiledPat->lastElementi();
-    opType = URX_TYPE(op);
-    if (opType != URX_STRING_LEN) {
+    if (split) {
+        fLiteralChars.truncate(indexOfLastCodePoint);
+        fixLiterals(FALSE);   // Recursive call, emit code to match the first part of the string.
+                              //  Note that the truncated literal string may be empty, in which case
+                              //  nothing will be emitted.
+
+        literalChar(lastCodePoint);  // Re-add the last code point as if it were a new literal.
+        fixLiterals(FALSE);          // Second recursive call, code for the final code point.
         return;
     }
-    stringLen = URX_VAL(op);
 
-    //
-    // Find the position of the last code point in the string  (might be a surrogate pair)
-    //
-    stringLastCharIdx = fRXPat->fLiteralText.length();
-    stringLastCharIdx = fRXPat->fLiteralText.moveIndex32(stringLastCharIdx, -1);
-    lastChar          = fRXPat->fLiteralText.char32At(stringLastCharIdx);
-
-    // The string should always be at least two code points long, meaning that there
-    //   should be something before the last char position that we just found.
-    U_ASSERT(stringLastCharIdx > stringStart);
-    stringNextToLastCharIdx = fRXPat->fLiteralText.moveIndex32(stringLastCharIdx, -1);
-    U_ASSERT(stringNextToLastCharIdx >= stringStart);
-    nextToLastChar          = fRXPat->fLiteralText.char32At(stringNextToLastCharIdx);
-
-    if (stringNextToLastCharIdx > stringStart) {
-        // The length of string remaining after removing one char is two or more.
-        // Leave the string in the compiled pattern, shorten it by one char,
-        //   and append a URX_ONECHAR op for the last char.
-        stringLen -= (fRXPat->fLiteralText.length() - stringLastCharIdx);
-        op = URX_BUILD(URX_STRING_LEN, stringLen);
-        fRXPat->fCompiledPat->setElementAt(op, fRXPat->fCompiledPat->size() -1);
-        emitONE_CHAR(lastChar);
+    // If we are doing case-insensitive matching, case fold the string.  This may expand
+    //   the string, e.g. the German sharp-s turns into "ss"
+    if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+        fLiteralChars.foldCase();
+        indexOfLastCodePoint = fLiteralChars.moveIndex32(fLiteralChars.length(), -1);
+        lastCodePoint = fLiteralChars.char32At(indexOfLastCodePoint);
+    }
+
+    if (indexOfLastCodePoint == 0) {
+        // Single character, emit a URX_ONECHAR op to match it.
+        if ((fModeFlags & UREGEX_CASE_INSENSITIVE) && 
+                 u_hasBinaryProperty(lastCodePoint, UCHAR_CASE_SENSITIVE)) {
+            op = URX_BUILD(URX_ONECHAR_I, lastCodePoint);
+        } else {
+            op = URX_BUILD(URX_ONECHAR, lastCodePoint);
+        }
+        fRXPat->fCompiledPat->addElement(op, *fStatus);
     } else {
-        // The original string consisted of exactly two characters.  Replace
-        // the existing compiled URX_STRING/URX_STRING_LEN ops with a pair
-        // of URX_ONECHARs.
-        fRXPat->fCompiledPat->setSize(fRXPat->fCompiledPat->size() -2);
-        emitONE_CHAR(nextToLastChar);
-        emitONE_CHAR(lastChar);
+        // Two or more chars, emit a URX_STRING to match them.
+        if (fModeFlags & UREGEX_CASE_INSENSITIVE) {
+            op = URX_BUILD(URX_STRING_I, fRXPat->fLiteralText.length());
+        } else {
+            // TODO here:  add optimization to split case sensitive strings of length two
+            //             into two single char ops, for efficiency.
+            op = URX_BUILD(URX_STRING, fRXPat->fLiteralText.length());
+        }
+        fRXPat->fCompiledPat->addElement(op, *fStatus);
+        op = URX_BUILD(URX_STRING_LEN, fLiteralChars.length());
+        fRXPat->fCompiledPat->addElement(op, *fStatus);
+        
+        // Add this string into the accumulated strings of the compiled pattern.
+        fRXPat->fLiteralText.append(fLiteralChars);
     }
+
+    fLiteralChars.remove();
 }
 
 
@@ -1937,7 +1898,7 @@ void    RegexCompile::fixLiterals(UBool split) {
 //
 //------------------------------------------------------------------------------
 void   RegexCompile::insertOp(int32_t where) {
-    UVector32 *code = fRXPat->fCompiledPat;
+    UVector64 *code = fRXPat->fCompiledPat;
     U_ASSERT(where>0 && where < code->size());
 
     int32_t  nop = URX_BUILD(URX_NOP, 0);
@@ -1947,7 +1908,7 @@ void   RegexCompile::insertOp(int32_t where) {
     //  were moved down by the insert.  Fix them.
     int32_t loc;
     for (loc=0; loc<code->size(); loc++) {
-        int32_t op = code->elementAti(loc);
+        int32_t op = (int32_t)code->elementAti(loc);
         int32_t opType = URX_TYPE(op);
         int32_t opValue = URX_VAL(op);
         if ((opType == URX_JMP         ||
@@ -1956,6 +1917,7 @@ void   RegexCompile::insertOp(int32_t where) {
             opType == URX_CTR_LOOP     ||
             opType == URX_CTR_LOOP_NG  ||
             opType == URX_JMP_SAV      ||
+            opType == URX_JMP_SAV_X    ||
             opType == URX_RELOC_OPRND)    && opValue > where) {
             // Target location for this opcode is after the insertion point and
             //   needs to be incremented to adjust for the insertion.
@@ -2006,6 +1968,8 @@ void   RegexCompile::insertOp(int32_t where) {
 //------------------------------------------------------------------------------
 int32_t   RegexCompile::blockTopLoc(UBool reserveLoc) {
     int32_t   theLoc;
+    fixLiterals(TRUE);  // Emit code for any pending literals.
+                        //   If last item was a string, emit separate op for the its last char.
     if (fRXPat->fCompiledPat->size() == fMatchCloseParen)
     {
         // The item just processed is a parenthesized block.
@@ -2014,13 +1978,17 @@ int32_t   RegexCompile::blockTopLoc(UBool reserveLoc) {
         U_ASSERT(URX_TYPE(((uint32_t)fRXPat->fCompiledPat->elementAti(theLoc))) == URX_NOP);
     }
     else {
-        // Item just compiled is a single thing, a ".", or a single char, or a set reference.
+        // Item just compiled is a single thing, a ".", or a single char, a string or a set reference.
         // No slot for STATE_SAVE was pre-reserved in the compiled code.
         // We need to make space now.
-        fixLiterals(TRUE);  // If last item was a string, separate the last char.
         theLoc = fRXPat->fCompiledPat->size()-1;
+        int32_t opAtTheLoc = (int32_t)fRXPat->fCompiledPat->elementAti(theLoc);
+        if (URX_TYPE(opAtTheLoc) == URX_STRING_LEN) {
+            // Strings take two opcode, we want the position of the first one.
+            // We can have a string at this point if a single character case-folded to two.
+            theLoc--;
+        }
         if (reserveLoc) {
-            /*int32_t opAtTheLoc = fRXPat->fCompiledPat->elementAti(theLoc);*/
             int32_t  nop = URX_BUILD(URX_NOP, 0);
             fRXPat->fCompiledPat->insertElementAt(nop, theLoc, *fStatus);
         }
@@ -2050,8 +2018,7 @@ void  RegexCompile::handleCloseParen() {
         return;
     }
 
-    // Force any literal chars that may follow the close paren to start a new string,
-    //   and not attach to any preceding it.
+    // Emit code for any pending literals.
     fixLiterals(FALSE);
 
     // Fixup any operations within the just-closed parenthesized group
@@ -2065,7 +2032,7 @@ void  RegexCompile::handleCloseParen() {
             break;
         }
         U_ASSERT(patIdx>0 && patIdx <= fRXPat->fCompiledPat->size());
-        patOp = fRXPat->fCompiledPat->elementAti(patIdx);
+        patOp = (int32_t)fRXPat->fCompiledPat->elementAti(patIdx);
         U_ASSERT(URX_VAL(patOp) == 0);          // Branch target for JMP should not be set.
         patOp |= fRXPat->fCompiledPat->size();  // Set it now.
         fRXPat->fCompiledPat->setElementAt(patOp, patIdx);
@@ -2093,7 +2060,7 @@ void  RegexCompile::handleCloseParen() {
         //   The frame offset of the variables for this cg is obtained from the
         //       start capture op and put it into the end-capture op.
         {
-            int32_t   captureOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
+            int32_t   captureOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
             U_ASSERT(URX_TYPE(captureOp) == URX_START_CAPTURE);
 
             int32_t   frameVarLocation = URX_VAL(captureOp);
@@ -2106,7 +2073,7 @@ void  RegexCompile::handleCloseParen() {
         //   Insert a LD_SP operation to restore the state stack to the position
         //   it was when the atomic parens were entered.
         {
-            int32_t   stoOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
+            int32_t   stoOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen+1);
             U_ASSERT(URX_TYPE(stoOp) == URX_STO_SP);
             int32_t   stoLoc = URX_VAL(stoOp);
             int32_t   ldOp   = URX_BUILD(URX_LD_SP, stoLoc);
@@ -2116,7 +2083,7 @@ void  RegexCompile::handleCloseParen() {
 
     case lookAhead:
         {
-            int32_t  startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
+            int32_t  startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
             U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
             int32_t dataLoc  = URX_VAL(startOp);
             int32_t op       = URX_BUILD(URX_LA_END, dataLoc);
@@ -2127,19 +2094,19 @@ void  RegexCompile::handleCloseParen() {
     case negLookAhead:
         {
             // See comment at doOpenLookAheadNeg
-            int32_t  startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-1);
+            int32_t  startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-1);
             U_ASSERT(URX_TYPE(startOp) == URX_LA_START);
             int32_t dataLoc  = URX_VAL(startOp);
             int32_t op       = URX_BUILD(URX_LA_END, dataLoc);
             fRXPat->fCompiledPat->addElement(op, *fStatus);
             op               = URX_BUILD(URX_BACKTRACK, 0);
             fRXPat->fCompiledPat->addElement(op, *fStatus);
-            op               = URX_BUILD(URX_LA_END, 0);
+            op               = URX_BUILD(URX_LA_END, dataLoc);
             fRXPat->fCompiledPat->addElement(op, *fStatus);
 
             // Patch the URX_SAVE near the top of the block.
             // The destination of the SAVE is the final LA_END that was just added.
-            int32_t saveOp   = fRXPat->fCompiledPat->elementAti(fMatchOpenParen);
+            int32_t saveOp   = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen);
             U_ASSERT(URX_TYPE(saveOp) == URX_STATE_SAVE);
             int32_t dest     = fRXPat->fCompiledPat->size()-1;
             saveOp           = URX_BUILD(URX_STATE_SAVE, dest);
@@ -2152,7 +2119,7 @@ void  RegexCompile::handleCloseParen() {
             // See comment at doOpenLookBehind.
 
             // Append the URX_LB_END and URX_LA_END to the compiled pattern.
-            int32_t  startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-4);
+            int32_t  startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-4);
             U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
             int32_t dataLoc  = URX_VAL(startOp);
             int32_t op       = URX_BUILD(URX_LB_END, dataLoc);
@@ -2187,7 +2154,7 @@ void  RegexCompile::handleCloseParen() {
             // See comment at doOpenLookBehindNeg.
 
             // Append the URX_LBN_END to the compiled pattern.
-            int32_t  startOp = fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
+            int32_t  startOp = (int32_t)fRXPat->fCompiledPat->elementAti(fMatchOpenParen-5);
             U_ASSERT(URX_TYPE(startOp) == URX_LB_START);
             int32_t dataLoc  = URX_VAL(startOp);
             int32_t op       = URX_BUILD(URX_LBN_END, dataLoc);
@@ -2248,7 +2215,6 @@ void        RegexCompile::compileSet(UnicodeSet *theSet)
     //      ignored strings, that would be better.)
     theSet->removeAllStrings();
     int32_t  setSize = theSet->size();
-    UChar32  firstSetChar = theSet->charAt(0);
 
     switch (setSize) {
     case 0:
@@ -2264,7 +2230,7 @@ void        RegexCompile::compileSet(UnicodeSet *theSet)
             // The set contains only a single code point.  Put it into
             //   the compiled pattern as a single char operation rather
             //   than a set, and discard the set itself.
-            literalChar(firstSetChar);
+            literalChar(theSet->charAt(0));
             delete theSet;
         }
         break;
@@ -2334,7 +2300,7 @@ void        RegexCompile::compileInterval(int32_t InitOp,  int32_t LoopOp)
     fRXPat->fCompiledPat->addElement(op, *fStatus);
 
     if ((fIntervalLow & 0xff000000) != 0 ||
-        fIntervalUpper > 0 && (fIntervalUpper & 0xff000000) != 0) {
+        (fIntervalUpper > 0 && (fIntervalUpper & 0xff000000) != 0)) {
             error(U_REGEX_NUMBER_TOO_BIG);
         }
 
@@ -2369,7 +2335,7 @@ UBool RegexCompile::compileInlineInterval() {
 
     // Pick up the opcode that is to be repeated
     //
-    int32_t op = fRXPat->fCompiledPat->elementAti(topOfBlock);
+    int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(topOfBlock);
 
     // Compute the pattern location where the inline sequence
     //   will end, and set up the state save op that will be needed.
@@ -2442,7 +2408,7 @@ void   RegexCompile::matchStartType() {
     }
 
     for (loc = 3; loc<end; loc++) {
-        op = fRXPat->fCompiledPat->elementAti(loc);
+        op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
         opType = URX_TYPE(op);
 
         // The loop is advancing linearly through the pattern.
@@ -2475,7 +2441,7 @@ void   RegexCompile::matchStartType() {
         case URX_STO_INP_LOC:
         case URX_BACKREF:         // BackRef.  Must assume that it might be a zero length match
         case URX_BACKREF_I:
-
+                
         case URX_STO_SP:          // Setup for atomic or possessive blocks.  Doesn't change what can match.
         case URX_LD_SP:
             break;
@@ -2592,11 +2558,17 @@ void   RegexCompile::matchStartType() {
             if (currentLen == 0) {
                 UChar32  c = URX_VAL(op);
                 if (u_hasBinaryProperty(c, UCHAR_CASE_SENSITIVE)) {
-                    // character may have distinct cased forms.  Add all of them
-                    //   to the set of possible starting match chars.
-                    UnicodeSet s(c, c);
-                    s.closeOver(USET_CASE_INSENSITIVE);
-                    fRXPat->fInitialChars->addAll(s);
+
+                    // Disable optimizations on first char of match.
+                    // TODO: Compute the set of chars that case fold to this char, or to
+                    //       a string that begins with this char.
+                    //       For simple case folding, this code worked:
+                    //   UnicodeSet s(c, c);
+                    //   s.closeOver(USET_CASE_INSENSITIVE);
+                    //   fRXPat->fInitialChars->addAll(s);
+
+                    fRXPat->fInitialChars->clear();
+                    fRXPat->fInitialChars->complement();
                 } else {
                     // Char has no case variants.  Just add it as-is to the
                     //   set of possible starting chars.
@@ -2681,7 +2653,7 @@ void   RegexCompile::matchStartType() {
         case URX_STRING:
             {
                 loc++;
-                int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+                int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
                 int32_t stringLen   = URX_VAL(stringLenOp);
                 U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
                 U_ASSERT(stringLenOp >= 2);
@@ -2710,7 +2682,7 @@ void   RegexCompile::matchStartType() {
                 //   attempt a string search for possible match positions.  But we
                 //   do update the set of possible starting characters.
                 loc++;
-                int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+                int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
                 int32_t stringLen   = URX_VAL(stringLenOp);
                 U_ASSERT(URX_TYPE(stringLenOp) == URX_STRING_LEN);
                 U_ASSERT(stringLenOp >= 2);
@@ -2720,7 +2692,13 @@ void   RegexCompile::matchStartType() {
                     int32_t stringStartIdx = URX_VAL(op);
                     UChar32  c = fRXPat->fLiteralText.char32At(stringStartIdx);
                     UnicodeSet s(c, c);
-                    s.closeOver(USET_CASE_INSENSITIVE);
+
+                    // TODO:  compute correct set of starting chars for full case folding.
+                    //        For the moment, say any char can start.
+                    // s.closeOver(USET_CASE_INSENSITIVE);
+                    s.clear();
+                    s.complement();
+
                     fRXPat->fInitialChars->addAll(s);
                     numInitialStrings += 2;  // Matching on an initial string not possible.
                 }
@@ -2739,9 +2717,9 @@ void   RegexCompile::matchStartType() {
                 //      move loc forwards to the end of the loop, skipping over the body.
                 //   If the min count is > 0,
                 //      continue normal processing of the body of the loop.
-                int32_t loopEndLoc   = fRXPat->fCompiledPat->elementAti(loc+1);
+                int32_t loopEndLoc   = (int32_t)fRXPat->fCompiledPat->elementAti(loc+1);
                         loopEndLoc   = URX_VAL(loopEndLoc);
-                int32_t minLoopCount = fRXPat->fCompiledPat->elementAti(loc+2);
+                int32_t minLoopCount = (int32_t)fRXPat->fCompiledPat->elementAti(loc+2);
                 if (minLoopCount == 0) {
                     // Min Loop Count of 0, treat like a forward branch and
                     //   move the current minimum length up to the target
@@ -2783,7 +2761,7 @@ void   RegexCompile::matchStartType() {
                 int32_t  depth = (opType == URX_LA_START? 2: 1);
                 for (;;) {
                     loc++;
-                    op = fRXPat->fCompiledPat->elementAti(loc);
+                    op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
                     if (URX_TYPE(op) == URX_LA_START) {
                         depth+=2;
                     }
@@ -2921,7 +2899,7 @@ int32_t   RegexCompile::minMatchLength(int32_t start, int32_t end) {
     }
 
     for (loc = start; loc<=end; loc++) {
-        op = fRXPat->fCompiledPat->elementAti(loc);
+        op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
         opType = URX_TYPE(op);
 
         // The loop is advancing linearly through the pattern.
@@ -3027,15 +3005,26 @@ int32_t   RegexCompile::minMatchLength(int32_t start, int32_t end) {
 
 
         case URX_STRING:
-        case URX_STRING_I:
             {
                 loc++;
-                int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
+                int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
                 currentLen += URX_VAL(stringLenOp);
             }
             break;
 
 
+        case URX_STRING_I:
+            {
+                loc++;
+                // TODO: with full case folding, matching input text may be shorter than
+                //       the string we have here.  More smarts could put some bounds on it.
+                //       Assume a min length of one for now.  A min length of zero causes
+                //        optimization failures for a pattern like "string"+
+                // currentLen += URX_VAL(stringLenOp);
+                currentLen += 1;
+            }
+            break;
+
         case URX_CTR_INIT:
         case URX_CTR_INIT_NG:
             {
@@ -3044,9 +3033,9 @@ int32_t   RegexCompile::minMatchLength(int32_t start, int32_t end) {
                 //      move loc forwards to the end of the loop, skipping over the body.
                 //   If the min count is > 0,
                 //      continue normal processing of the body of the loop.
-                int32_t loopEndLoc   = fRXPat->fCompiledPat->elementAti(loc+1);
+                int32_t loopEndLoc   = (int32_t)fRXPat->fCompiledPat->elementAti(loc+1);
                         loopEndLoc   = URX_VAL(loopEndLoc);
-                int32_t minLoopCount = fRXPat->fCompiledPat->elementAti(loc+2);
+                int32_t minLoopCount = (int32_t)fRXPat->fCompiledPat->elementAti(loc+2);
                 if (minLoopCount == 0) {
                     loc = loopEndLoc;
                 } else {
@@ -3081,7 +3070,7 @@ int32_t   RegexCompile::minMatchLength(int32_t start, int32_t end) {
                 int32_t  depth = (opType == URX_LA_START? 2: 1);;
                 for (;;) {
                     loc++;
-                    op = fRXPat->fCompiledPat->elementAti(loc);
+                    op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
                     if (URX_TYPE(op) == URX_LA_START) {
                         // The boilerplate for look-ahead includes two LA_END insturctions,
                         //    Depth will be decremented by each one when it is seen.
@@ -3142,6 +3131,16 @@ int32_t   RegexCompile::minMatchLength(int32_t start, int32_t end) {
     return currentLen;
 }
 
+// Increment with overflow check.
+// val and delta will both be positive.
+
+static int32_t safeIncrement(int32_t val, int32_t delta) {
+    if (INT32_MAX - val > delta) {
+        return val + delta;
+    } else {
+        return INT32_MAX;
+    }
+}
 
 
 //------------------------------------------------------------------------------
@@ -3175,7 +3174,7 @@ int32_t   RegexCompile::maxMatchLength(int32_t start, int32_t end) {
     }
 
     for (loc = start; loc<=end; loc++) {
-        op = fRXPat->fCompiledPat->elementAti(loc);
+        op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
         opType = URX_TYPE(op);
 
         // The loop is advancing linearly through the pattern.
@@ -3238,15 +3237,15 @@ int32_t   RegexCompile::maxMatchLength(int32_t start, int32_t end) {
         case URX_DOTANY_ALL:
         case URX_DOTANY:
         case URX_DOTANY_UNIX:
-            currentLen+=2;
+            currentLen = safeIncrement(currentLen, 2);
             break;
 
             // Single literal character.  Increase current max length by one or two,
             //       depending on whether the char is in the supplementary range.
         case URX_ONECHAR:
-            currentLen++;
+            currentLen = safeIncrement(currentLen, 1);
             if (URX_VAL(op) > 0x10000) {
-                currentLen++;
+                currentLen = safeIncrement(currentLen, 1);
             }
             break;
 
@@ -3299,15 +3298,41 @@ int32_t   RegexCompile::maxMatchLength(int32_t start, int32_t end) {
 
 
         case URX_STRING:
+            {
+                loc++;
+                int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
+                currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
+                break;
+            }
+
         case URX_STRING_I:
+            // TODO:  This code assumes that any user string that matches will be no longer
+            //        than our compiled string, with case insensitive matching.
+            //        Our compiled string has been case-folded already.
+            //
+            //        Any matching user string will have no more code points than our
+            //        compiled (folded) string.  Folding may add code points, but
+            //        not remove them.
+            //
+            //        There is a potential problem if a supplemental code point 
+            //        case-folds to a BMP code point.  In this case our compiled string
+            //        could be shorter (in code units) than a matching user string.
+            //
+            //        At this time (Unicode 6.1) there are no such characters, and this case
+            //        is not being handled.  A test, intltest regex/Bug9283, will fail if
+            //        any problematic characters are added to Unicode.
+            //
+            //        If this happens, we can make a set of the BMP chars that the
+            //        troublesome supplementals fold to, scan our string, and bump the
+            //        currentLen one extra for each that is found.
+            //
             {
                 loc++;
-                int32_t stringLenOp = fRXPat->fCompiledPat->elementAti(loc);
-                currentLen += URX_VAL(stringLenOp);
+                int32_t stringLenOp = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
+                currentLen = safeIncrement(currentLen, URX_VAL(stringLenOp));
             }
             break;
 
-
         case URX_CTR_INIT:
         case URX_CTR_INIT_NG:
         case URX_CTR_LOOP:
@@ -3342,7 +3367,7 @@ int32_t   RegexCompile::maxMatchLength(int32_t start, int32_t end) {
                 int32_t  depth = 0;
                 for (;;) {
                     loc++;
-                    op = fRXPat->fCompiledPat->elementAti(loc);
+                    op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
                     if (URX_TYPE(op) == URX_LA_START || URX_TYPE(op) == URX_LB_START) {
                         depth++;
                     }
@@ -3381,6 +3406,10 @@ int32_t   RegexCompile::maxMatchLength(int32_t start, int32_t end) {
 //                code generation to provide locations that may be patched later.
 //                Many end up unneeded, and are removed by this function.
 //
+//                In order to minimize the number of passes through the pattern,
+//                back-reference fixup is also performed here (adjusting
+//                back-reference operands to point to the correct frame offsets).
+//
 //------------------------------------------------------------------------------
 void RegexCompile::stripNOPs() {
 
@@ -3397,11 +3426,13 @@ void RegexCompile::stripNOPs() {
     int32_t   d = 0;
     for (loc=0; loc<end; loc++) {
         deltas.addElement(d, *fStatus);
-        int32_t op = fRXPat->fCompiledPat->elementAti(loc);
+        int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(loc);
         if (URX_TYPE(op) == URX_NOP) {
             d++;
         }
     }
+    
+    UnicodeString caseStringBuffer;
 
     // Make a second pass over the code, removing the NOPs by moving following
     //  code up, and patching operands that refer to code locations that
@@ -3410,7 +3441,7 @@ void RegexCompile::stripNOPs() {
     int32_t src;
     int32_t dst = 0;
     for (src=0; src<end; src++) {
-        int32_t op = fRXPat->fCompiledPat->elementAti(src);
+        int32_t op = (int32_t)fRXPat->fCompiledPat->elementAti(src);
         int32_t opType = URX_TYPE(op);
         switch (opType) {
         case URX_NOP:
@@ -3435,6 +3466,22 @@ void RegexCompile::stripNOPs() {
                 break;
             }
 
+        case URX_BACKREF:
+        case URX_BACKREF_I:
+            {
+                int32_t where = URX_VAL(op);
+                if (where > fRXPat->fGroupMap->size()) {
+                    error(U_REGEX_INVALID_BACK_REF);
+                    break;
+                }
+                where = fRXPat->fGroupMap->elementAti(where-1);
+                op    = URX_BUILD(opType, where);
+                fRXPat->fCompiledPat->setElementAt(op, dst);
+                dst++;
+                
+                fRXPat->fNeedsAltInput = TRUE;
+                break;
+            }
         case URX_RESERVED_OP:
         case URX_RESERVED_OP_N:
         case URX_BACKTRACK:
@@ -3463,13 +3510,11 @@ void RegexCompile::stripNOPs() {
         case URX_DOTANY_UNIX:
         case URX_STO_SP:
         case URX_LD_SP:
-        case URX_BACKREF:
         case URX_STO_INP_LOC:
         case URX_LA_START:
         case URX_LA_END:
         case URX_ONECHAR_I:
         case URX_STRING_I:
-        case URX_BACKREF_I:
         case URX_DOLLAR_M:
         case URX_CARET_M:
         case URX_CARET_M_UNIX:
@@ -3510,17 +3555,29 @@ void RegexCompile::stripNOPs() {
 void RegexCompile::error(UErrorCode e) {
     if (U_SUCCESS(*fStatus)) {
         *fStatus = e;
-        fParseErr->line   = fLineNum;
-        fParseErr->offset = fCharNum;
+        // Hmm. fParseErr (UParseError) line & offset fields are int32_t in public
+        // API (see common/unicode/parseerr.h), while fLineNum and fCharNum are
+        // int64_t. If the values of the latter are out of range for the former,
+        // set them to the appropriate "field not supported" values.
+        if (fLineNum > 0x7FFFFFFF) {
+            fParseErr->line   = 0;
+            fParseErr->offset = -1;
+        } else if (fCharNum > 0x7FFFFFFF) {
+            fParseErr->line   = (int32_t)fLineNum;
+            fParseErr->offset = -1;
+        } else {
+            fParseErr->line   = (int32_t)fLineNum;
+            fParseErr->offset = (int32_t)fCharNum;
+        }
+        
+        UErrorCode status = U_ZERO_ERROR; // throwaway status for extracting context
 
         // Fill in the context.
         //   Note: extractBetween() pins supplied indicies to the string bounds.
         uprv_memset(fParseErr->preContext,  0, sizeof(fParseErr->preContext));
         uprv_memset(fParseErr->postContext, 0, sizeof(fParseErr->postContext));
-        fRXPat->fPattern.extractBetween(fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex,
-            fParseErr->preContext,  0);
-        fRXPat->fPattern.extractBetween(fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1,
-            fParseErr->postContext, 0);
+        utext_extract(fRXPat->fPattern, fScanIndex-U_PARSE_CONTEXT_LEN+1, fScanIndex, fParseErr->preContext, U_PARSE_CONTEXT_LEN, &status);
+        utext_extract(fRXPat->fPattern, fScanIndex, fScanIndex+U_PARSE_CONTEXT_LEN-1, fParseErr->postContext, U_PARSE_CONTEXT_LEN, &status);
     }
 }
 
@@ -3538,10 +3595,10 @@ static const UChar      chDigit7    = 0x37;      // '9'
 static const UChar      chColon     = 0x3A;      // ':'
 static const UChar      chE         = 0x45;      // 'E'
 static const UChar      chQ         = 0x51;      // 'Q'
-static const UChar      chN         = 0x4E;      // 'N'
+//static const UChar      chN         = 0x4E;      // 'N'
 static const UChar      chP         = 0x50;      // 'P'
 static const UChar      chBackSlash = 0x5c;      // '\'  introduces a char escape
-static const UChar      chLBracket  = 0x5b;      // '['
+//static const UChar      chLBracket  = 0x5b;      // '['
 static const UChar      chRBracket  = 0x5d;      // ']'
 static const UChar      chUp        = 0x5e;      // '^'
 static const UChar      chLowerP    = 0x70;
@@ -3560,23 +3617,23 @@ static const UChar      chLS        = 0x2028;    //    Unicode Line Separator
 //------------------------------------------------------------------------------
 UChar32  RegexCompile::nextCharLL() {
     UChar32       ch;
-    UnicodeString &pattern = fRXPat->fPattern;
 
     if (fPeekChar != -1) {
         ch = fPeekChar;
         fPeekChar = -1;
         return ch;
     }
-    if (fPatternLength==0 || fNextIndex >= fPatternLength) {
-        return (UChar32)-1;
+    
+    // assume we're already in the right place
+    ch = UTEXT_NEXT32(fRXPat->fPattern);
+    if (ch == U_SENTINEL) {
+        return ch;
     }
-    ch         = pattern.char32At(fNextIndex);
-    fNextIndex = pattern.moveIndex32(fNextIndex, 1);
 
     if (ch == chCR ||
         ch == chNEL ||
         ch == chLS   ||
-        ch == chLF && fLastChar != chCR) {
+        (ch == chLF && fLastChar != chCR)) {
         // Character is starting a new line.  Bump up the line number, and
         //  reset the column to 0.
         fLineNum++;
@@ -3616,16 +3673,17 @@ UChar32  RegexCompile::peekCharLL() {
 //------------------------------------------------------------------------------
 void RegexCompile::nextChar(RegexPatternChar &c) {
 
-    fScanIndex = fNextIndex;
+    fScanIndex = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
     c.fChar    = nextCharLL();
     c.fQuoted  = FALSE;
 
     if (fQuoteMode) {
         c.fQuoted = TRUE;
-        if ((c.fChar==chBackSlash && peekCharLL()==chE) || c.fChar == (UChar32)-1) {
+        if ((c.fChar==chBackSlash && peekCharLL()==chE && ((fModeFlags & UREGEX_LITERAL) == 0)) || 
+            c.fChar == (UChar32)-1) {
             fQuoteMode = FALSE;  //  Exit quote mode,
-            nextCharLL();       // discard the E
-            nextChar(c);        // recurse to get the real next char
+            nextCharLL();        // discard the E
+            nextChar(c);         // recurse to get the real next char
         }
     }
     else if (fInBackslashQuote) {
@@ -3662,7 +3720,7 @@ void RegexCompile::nextChar(RegexPatternChar &c) {
                     }
                 }
                 // TODO:  check what Java & Perl do with non-ASCII white spaces.  Ticket 6061.
-                if (uprv_isRuleWhiteSpace(c.fChar) == FALSE) {
+                if (PatternProps::isWhiteSpace(c.fChar) == FALSE) {
                     break;
                 }
                 c.fChar = nextCharLL();
@@ -3673,8 +3731,7 @@ void RegexCompile::nextChar(RegexPatternChar &c) {
         //  check for backslash escaped characters.
         //
         if (c.fChar == chBackSlash) {
-            int32_t startX = fNextIndex;  // start and end positions of the
-            int32_t endX   = fNextIndex;  //   sequence following the '\'
+            int64_t pos = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
             if (RegexStaticSets::gStaticSets->fUnescapeCharSet.contains(peekCharLL())) {
                 //
                 // A '\' sequence that is handled by ICU's standard unescapeAt function.
@@ -3683,19 +3740,39 @@ void RegexCompile::nextChar(RegexPatternChar &c) {
                 //
                 nextCharLL();                 // get & discard the peeked char.
                 c.fQuoted = TRUE;
-                c.fChar = fRXPat->fPattern.unescapeAt(endX);
-                if (startX == endX) {
-                    error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+                
+                if (UTEXT_FULL_TEXT_IN_CHUNK(fRXPat->fPattern, fPatternLength)) {
+                    int32_t endIndex = (int32_t)pos;
+                    c.fChar = u_unescapeAt(uregex_ucstr_unescape_charAt, &endIndex, (int32_t)fPatternLength, (void *)fRXPat->fPattern->chunkContents);
+                    
+                    if (endIndex == pos) {
+                        error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+                    }
+                    fCharNum += endIndex - pos;
+                    UTEXT_SETNATIVEINDEX(fRXPat->fPattern, endIndex);
+                } else {
+                    int32_t offset = 0;
+                    struct URegexUTextUnescapeCharContext context = U_REGEX_UTEXT_UNESCAPE_CONTEXT(fRXPat->fPattern);
+                    
+                    UTEXT_SETNATIVEINDEX(fRXPat->fPattern, pos);
+                    c.fChar = u_unescapeAt(uregex_utext_unescape_charAt, &offset, INT32_MAX, &context);
+
+                    if (offset == 0) {
+                        error(U_REGEX_BAD_ESCAPE_SEQUENCE);
+                    } else if (context.lastOffset == offset) {
+                        UTEXT_PREVIOUS32(fRXPat->fPattern);
+                    } else if (context.lastOffset != offset-1) {
+                        utext_moveIndex32(fRXPat->fPattern, offset - context.lastOffset - 1);
+                    }
+                    fCharNum += offset;
                 }
-                fCharNum += endX - startX;
-                fNextIndex = endX;
             }
             else if (peekCharLL() == chDigit0) {
                 //  Octal Escape, using Java Regexp Conventions
                 //    which are \0 followed by 1-3 octal digits.
                 //    Different from ICU Unescape handling of Octal, which does not
                 //    require the leading 0.
-                //  Java also has the convention of only consuning 2 octal digits if
+                //  Java also has the convention of only consuming 2 octal digits if
                 //    the three digit number would be > 0xff
                 //
                 c.fChar = 0;
@@ -3876,13 +3953,13 @@ UnicodeSet *RegexCompile::scanPosixProp() {
 
     // Save the scanner state.
     // TODO:  move this into the scanner, with the state encapsulated in some way.  Ticket 6062
-    int32_t     savedScanIndex        = fScanIndex;
-    int32_t     savedNextIndex        = fNextIndex;
+    int64_t     savedScanIndex        = fScanIndex;
+    int64_t     savedNextIndex        = UTEXT_GETNATIVEINDEX(fRXPat->fPattern);
     UBool       savedQuoteMode        = fQuoteMode;
     UBool       savedInBackslashQuote = fInBackslashQuote;
     UBool       savedEOLComments      = fEOLComments;
-    int32_t     savedLineNum          = fLineNum;
-    int32_t     savedCharNum          = fCharNum;
+    int64_t     savedLineNum          = fLineNum;
+    int64_t     savedCharNum          = fCharNum;
     UChar32     savedLastChar         = fLastChar;
     UChar32     savedPeekChar         = fPeekChar;
     RegexPatternChar savedfC          = fC;
@@ -3929,7 +4006,6 @@ UnicodeSet *RegexCompile::scanPosixProp() {
         //  The main scanner will retry the input as a normal set expression,
         //    not a [:Property:] expression.
         fScanIndex        = savedScanIndex;
-        fNextIndex        = savedNextIndex;
         fQuoteMode        = savedQuoteMode;
         fInBackslashQuote = savedInBackslashQuote;
         fEOLComments      = savedEOLComments;
@@ -3938,6 +4014,7 @@ UnicodeSet *RegexCompile::scanPosixProp() {
         fLastChar         = savedLastChar;
         fPeekChar         = savedPeekChar;
         fC                = savedfC;
+        UTEXT_SETNATIVEINDEX(fRXPat->fPattern, savedNextIndex);
     }
     return uset;
 }
@@ -3987,7 +4064,25 @@ UnicodeSet *RegexCompile::createSetForProperty(const UnicodeString &propName, UB
     
     //
     //  The property as it was didn't work.
-    //    Do emergency fixes -
+
+    //  Do [:word:]. It is not recognized as a property by UnicodeSet.  "word" not standard POSIX 
+    //     or standard Java, but many other regular expression packages do recognize it.
+    
+    if (propName.caseCompare(UNICODE_STRING_SIMPLE("word"), 0) == 0) {
+        *fStatus = U_ZERO_ERROR;
+        set = new UnicodeSet(*(fRXPat->fStaticSets[URX_ISWORD_SET]));
+        if (set == NULL) {
+            *fStatus = U_MEMORY_ALLOCATION_ERROR;
+            return set;
+        }
+        if (negated) {
+            set->complement();
+        }
+        return set;
+    }
+
+
+    //    Do Java fixes -
     //       InGreek -> InGreek or Coptic, that being the official Unicode name for that block.
     //       InCombiningMarksforSymbols -> InCombiningDiacriticalMarksforSymbols.
     //