]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/nfrule.cpp
ICU-531.31.tar.gz
[apple/icu.git] / icuSources / i18n / nfrule.cpp
index d6cf1850f486f832095ee180e5db79e9c4bc9802..c2d6526413004a779a3d729cae7b231f5c1a0cd3 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-*   Copyright (C) 1997-2006, International Business Machines
+*   Copyright (C) 1997-2014, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ******************************************************************************
 *   file name:  nfrule.cpp
@@ -17,6 +17,7 @@
 
 #if U_HAVE_RBNF
 
+#include "unicode/localpointer.h"
 #include "unicode/rbnf.h"
 #include "unicode/tblcoll.h"
 #include "unicode/coleitr.h"
@@ -24,8 +25,7 @@
 #include "nfrs.h"
 #include "nfrlist.h"
 #include "nfsubs.h"
-
-#include "util.h"
+#include "patternprops.h"
 
 U_NAMESPACE_BEGIN
 
@@ -77,7 +77,6 @@ static const UChar gGreaterZero[] =             {0x3E, 0x30, 0};    /* ">0" */
 static const UChar gEqualPercent[] =            {0x3D, 0x25, 0};    /* "=%" */
 static const UChar gEqualHash[] =               {0x3D, 0x23, 0};    /* "=#" */
 static const UChar gEqualZero[] =               {0x3D, 0x30, 0};    /* "=0" */
-static const UChar gEmptyString[] =             {0};                /* "" */
 static const UChar gGreaterGreaterGreater[] =   {0x3E, 0x3E, 0x3E, 0}; /* ">>>" */
 
 static const UChar * const tokenStrings[] = {
@@ -235,7 +234,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
         descriptor.setTo(description, 0, p);
 
         ++p;
-        while (p < description.length() && uprv_isRuleWhiteSpace(description.charAt(p))) {
+        while (p < description.length() && PatternProps::isWhiteSpace(description.charAt(p))) {
             ++p;
         }
         description.removeBetween(0, p);
@@ -243,16 +242,16 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
         // check first to see if the rule descriptor matches the token
         // for one of the special rules.  If it does, set the base
         // value to the correct identfier value
-        if (descriptor == gMinusX) {
+        if (0 == descriptor.compare(gMinusX, 2)) {
             setType(kNegativeNumberRule);
         }
-        else if (descriptor == gXDotX) {
+        else if (0 == descriptor.compare(gXDotX, 3)) {
             setType(kImproperFractionRule);
         }
-        else if (descriptor == gZeroDotX) {
+        else if (0 == descriptor.compare(gZeroDotX, 3)) {
             setType(kProperFractionRule);
         }
-        else if (descriptor == gXDotZero) {
+        else if (0 == descriptor.compare(gXDotZero, 3)) {
             setType(kMasterRule);
         }
 
@@ -278,7 +277,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
                 else if (c == gSlash || c == gGreaterThan) {
                     break;
                 }
-                else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+                else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gDot) {
                 }
                 else {
                     // throw new IllegalArgumentException("Illegal character in rule descriptor");
@@ -307,7 +306,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
                     else if (c == gGreaterThan) {
                         break;
                     }
-                    else if (uprv_isRuleWhiteSpace(c) || c == gComma || c == gDot) {
+                    else if (PatternProps::isWhiteSpace(c) || c == gComma || c == gDot) {
                     }
                     else {
                         // throw new IllegalArgumentException("Illegal character is rule descriptor");
@@ -410,12 +409,12 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
     // at the end of the rule text
     if (subStart == -1) {
         return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
-            ruleSet, rbnf, gEmptyString, status);
+            ruleSet, rbnf, UnicodeString(), status);
     }
 
     // special-case the ">>>" token, since searching for the > at the
     // end will actually find the > in the middle
-    if (ruleText.indexOf(gGreaterGreaterGreater) == subStart) {
+    if (ruleText.indexOf(gGreaterGreaterGreater, 3, 0) == subStart) {
         subEnd = subStart + 2;
 
         // otherwise the substitution token ends with the same character
@@ -438,7 +437,7 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
     // at the end of the rule
     if (subEnd == -1) {
         return NFSubstitution::makeSubstitution(ruleText.length(), this, predecessor,
-            ruleSet, rbnf, gEmptyString, status);
+            ruleSet, rbnf, UnicodeString(), status);
     }
 
     // if we get here, we have a real substitution token (or at least
@@ -582,10 +581,10 @@ void
 NFRule::_appendRuleText(UnicodeString& result) const
 {
     switch (getType()) {
-    case kNegativeNumberRule: result.append(gMinusX); break;
-    case kImproperFractionRule: result.append(gXDotX); break;
-    case kProperFractionRule: result.append(gZeroDotX); break;
-    case kMasterRule: result.append(gXDotZero); break;
+    case kNegativeNumberRule: result.append(gMinusX, 2); break;
+    case kImproperFractionRule: result.append(gXDotX, 3); break;
+    case kProperFractionRule: result.append(gZeroDotX, 3); break;
+    case kMasterRule: result.append(gXDotZero, 3); break;
     default:
         // for a normal rule, write out its base value, and if the radix is
         // something other than 10, write out the radix (with the preceding
@@ -610,7 +609,7 @@ NFRule::_appendRuleText(UnicodeString& result) const
     // if the rule text begins with a space, write an apostrophe
     // (whitespace after the rule descriptor is ignored; the
     // apostrophe is used to make the whitespace significant)
-    if (ruleText.startsWith(gSpace) && sub1->getPos() != 0) {
+    if (ruleText.charAt(0) == gSpace && sub1->getPos() != 0) {
         result.append(gTick);
     }
 
@@ -743,10 +742,12 @@ NFRule::shouldRollBack(double number) const
 static void dumpUS(FILE* f, const UnicodeString& us) {
   int len = us.length();
   char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
-  us.extract(0, len, buf);
-  buf[len] = 0;
-  fprintf(f, "%s", buf);
-  uprv_free(buf); //delete[] buf;
+  if (buf != NULL) {
+         us.extract(0, len, buf);
+         buf[len] = 0;
+         fprintf(f, "%s", buf);
+         uprv_free(buf); //delete[] buf;
+  }
 }
 #endif
 
@@ -755,7 +756,8 @@ NFRule::doParse(const UnicodeString& text,
                 ParsePosition& parsePosition,
                 UBool isFractionRule,
                 double upperBound,
-                Formattable& resVal) const
+                Formattable& resVal,
+                UBool isDecimFmtParseable) const
 {
     // internally we operate on a copy of the string being parsed
     // (because we're going to change it) and use our own ParsePosition
@@ -797,6 +799,17 @@ NFRule::doParse(const UnicodeString& text,
         return TRUE;
     }
 
+    // Detect when this rule's main job is to parse a decimal format and we're not
+    // supposed to.
+    if (!isDecimFmtParseable) {
+       // The following tries to detect a rule like "x.x: =#,##0.#=;"
+        if ( sub1->isDecimalFormatSubstitutionOnly() && sub2->isRuleSetSubstitutionOnly() ) {
+            parsePosition.setErrorIndex(pp.getErrorIndex());
+            resVal.setLong(0);
+            return TRUE;
+        }
+    }
+
     // this is the fun part.  The basic guts of the rule-matching
     // logic is matchToDelimiter(), which is called twice.  The first
     // time it searches the input string for the rule text BETWEEN
@@ -946,11 +959,15 @@ NFRule::stripPrefix(UnicodeString& text, const UnicodeString& prefix, ParsePosit
 {
     // if the prefix text is empty, dump out without doing anything
     if (prefix.length() != 0) {
+       UErrorCode status = U_ZERO_ERROR;
         // use prefixLength() to match the beginning of
         // "text" against "prefix".  This function returns the
         // number of characters from "text" that matched (or 0 if
         // we didn't match the whole prefix)
-        int32_t pfl = prefixLength(text, prefix);
+        int32_t pfl = prefixLength(text, prefix, status);
+        if (U_FAILURE(status)) { // Memory allocation error.
+               return;
+        }
         if (pfl != 0) {
             // if we got a successful match, update the parse position
             // and strip the prefix off of "text"
@@ -998,11 +1015,15 @@ NFRule::matchToDelimiter(const UnicodeString& text,
                          const NFSubstitution* sub,
                          double upperBound) const
 {
+       UErrorCode status = U_ZERO_ERROR;
     // if "delimiter" contains real (i.e., non-ignorable) text, search
     // it for "delimiter" beginning at "start".  If that succeeds, then
     // use "sub"'s doParse() method to match the text before the
     // instance of "delimiter" we just found.
-    if (!allIgnorable(delimiter)) {
+    if (!allIgnorable(delimiter, status)) {
+       if (U_FAILURE(status)) { //Memory allocation error.
+               return 0;
+       }
         ParsePosition tempPP;
         Formattable result;
 
@@ -1110,7 +1131,7 @@ NFRule::matchToDelimiter(const UnicodeString& text,
 * text with a collator).  If there's no match, this is 0.
 */
 int32_t
-NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) const
+NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix, UErrorCode& status) const
 {
     // if we're looking for an empty prefix, it obviously matches
     // zero characters.  Just go ahead and return 0.
@@ -1128,9 +1149,18 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) cons
         // isn't a RuleBasedCollator, because RuleBasedCollator defines
         // the CollationElementIterator protocol.  Hopefully, this
         // will change someday.)
-        RuleBasedCollator* collator = (RuleBasedCollator*)formatter->getCollator();
-        CollationElementIterator* strIter = collator->createCollationElementIterator(str);
-        CollationElementIterator* prefixIter = collator->createCollationElementIterator(prefix);
+        const RuleBasedCollator* collator = formatter->getCollator();
+        if (collator == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
+        LocalPointer<CollationElementIterator> strIter(collator->createCollationElementIterator(str));
+        LocalPointer<CollationElementIterator> prefixIter(collator->createCollationElementIterator(prefix));
+        // Check for memory allocation error.
+        if (strIter.isNull() || prefixIter.isNull()) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return 0;
+        }
 
         UErrorCode err = U_ZERO_ERROR;
 
@@ -1181,8 +1211,6 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) cons
             // if skipping over ignorables brought us to the end
             // of the target string, we didn't match and return 0
             if (oStr == CollationElementIterator::NULLORDER) {
-                delete prefixIter;
-                delete strIter;
                 return 0;
             }
 
@@ -1191,8 +1219,6 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) cons
             // get a mismatch, dump out and return 0
             if (CollationElementIterator::primaryOrder(oStr)
                 != CollationElementIterator::primaryOrder(oPrefix)) {
-                delete prefixIter;
-                delete strIter;
                 return 0;
 
                 // otherwise, advance to the next character in each string
@@ -1212,9 +1238,6 @@ NFRule::prefixLength(const UnicodeString& str, const UnicodeString& prefix) cons
 #ifdef RBNF_DEBUG
         fprintf(stderr, "prefix length: %d\n", result);
 #endif
-        delete prefixIter;
-        delete strIter;
-
         return result;
 #if 0
         //----------------------------------------------------------------
@@ -1329,9 +1352,13 @@ NFRule::findText(const UnicodeString& str,
         // slow, but it will locate the key and tell use how long the
         // matching text was.
         UnicodeString temp;
+        UErrorCode status = U_ZERO_ERROR;
         while (p < str.length() && keyLen == 0) {
             temp.setTo(str, p, str.length() - p);
-            keyLen = prefixLength(temp, key);
+            keyLen = prefixLength(temp, key, status);
+            if (U_FAILURE(status)) {
+               break;
+            }
             if (keyLen != 0) {
                 *length = keyLen;
                 return p;
@@ -1406,7 +1433,7 @@ NFRule::findText(const UnicodeString& str,
 * ignorable at the primary-order level.  false otherwise.
 */
 UBool
-NFRule::allIgnorable(const UnicodeString& str) const
+NFRule::allIgnorable(const UnicodeString& str, UErrorCode& status) const
 {
     // if the string is empty, we can just return true
     if (str.length() == 0) {
@@ -1418,8 +1445,18 @@ NFRule::allIgnorable(const UnicodeString& str) const
     // a collation element iterator and make sure each collation
     // element is 0 (ignorable) at the primary level
     if (formatter->isLenient()) {
-        RuleBasedCollator* collator = (RuleBasedCollator*)(formatter->getCollator());
-        CollationElementIterator* iter = collator->createCollationElementIterator(str);
+        const RuleBasedCollator* collator = formatter->getCollator();
+        if (collator == NULL) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return FALSE;
+        }
+        LocalPointer<CollationElementIterator> iter(collator->createCollationElementIterator(str));
+
+        // Memory allocation error check.
+        if (iter.isNull()) {
+            status = U_MEMORY_ALLOCATION_ERROR;
+            return FALSE;
+        }
 
         UErrorCode err = U_ZERO_ERROR;
         int32_t o = iter->next(err);
@@ -1428,7 +1465,6 @@ NFRule::allIgnorable(const UnicodeString& str) const
             o = iter->next(err);
         }
 
-        delete iter;
         return o == CollationElementIterator::NULLORDER;
     }
 #endif
@@ -1442,5 +1478,3 @@ U_NAMESPACE_END
 
 /* U_HAVE_RBNF */
 #endif
-
-