1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/intl/icu/source/i18n/cpdtrans.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,614 @@ 1.4 +/* 1.5 +********************************************************************** 1.6 +* Copyright (C) 1999-2011, International Business Machines 1.7 +* Corporation and others. All Rights Reserved. 1.8 +********************************************************************** 1.9 +* Date Name Description 1.10 +* 11/17/99 aliu Creation. 1.11 +********************************************************************** 1.12 +*/ 1.13 + 1.14 +#include "unicode/utypes.h" 1.15 + 1.16 +#if !UCONFIG_NO_TRANSLITERATION 1.17 + 1.18 +#include "unicode/unifilt.h" 1.19 +#include "unicode/uniset.h" 1.20 +#include "cpdtrans.h" 1.21 +#include "uvector.h" 1.22 +#include "tridpars.h" 1.23 +#include "cmemory.h" 1.24 + 1.25 +// keep in sync with Transliterator 1.26 +//static const UChar ID_SEP = 0x002D; /*-*/ 1.27 +static const UChar ID_DELIM = 0x003B; /*;*/ 1.28 +static const UChar NEWLINE = 10; 1.29 + 1.30 +static const UChar COLON_COLON[] = {0x3A, 0x3A, 0}; //"::" 1.31 + 1.32 +U_NAMESPACE_BEGIN 1.33 + 1.34 +const UChar CompoundTransliterator::PASS_STRING[] = { 0x0025, 0x0050, 0x0061, 0x0073, 0x0073, 0 }; // "%Pass" 1.35 + 1.36 +UOBJECT_DEFINE_RTTI_IMPLEMENTATION(CompoundTransliterator) 1.37 + 1.38 +/** 1.39 + * Constructs a new compound transliterator given an array of 1.40 + * transliterators. The array of transliterators may be of any 1.41 + * length, including zero or one, however, useful compound 1.42 + * transliterators have at least two components. 1.43 + * @param transliterators array of <code>Transliterator</code> 1.44 + * objects 1.45 + * @param transliteratorCount The number of 1.46 + * <code>Transliterator</code> objects in transliterators. 1.47 + * @param filter the filter. Any character for which 1.48 + * <tt>filter.contains()</tt> returns <tt>false</tt> will not be 1.49 + * altered by this transliterator. If <tt>filter</tt> is 1.50 + * <tt>null</tt> then no filtering is applied. 1.51 + */ 1.52 +CompoundTransliterator::CompoundTransliterator( 1.53 + Transliterator* const transliterators[], 1.54 + int32_t transliteratorCount, 1.55 + UnicodeFilter* adoptedFilter) : 1.56 + Transliterator(joinIDs(transliterators, transliteratorCount), adoptedFilter), 1.57 + trans(0), count(0), numAnonymousRBTs(0) { 1.58 + setTransliterators(transliterators, transliteratorCount); 1.59 +} 1.60 + 1.61 +/** 1.62 + * Splits an ID of the form "ID;ID;..." into a compound using each 1.63 + * of the IDs. 1.64 + * @param id of above form 1.65 + * @param forward if false, does the list in reverse order, and 1.66 + * takes the inverse of each ID. 1.67 + */ 1.68 +CompoundTransliterator::CompoundTransliterator(const UnicodeString& id, 1.69 + UTransDirection direction, 1.70 + UnicodeFilter* adoptedFilter, 1.71 + UParseError& /*parseError*/, 1.72 + UErrorCode& status) : 1.73 + Transliterator(id, adoptedFilter), 1.74 + trans(0), numAnonymousRBTs(0) { 1.75 + // TODO add code for parseError...currently unused, but 1.76 + // later may be used by parsing code... 1.77 + init(id, direction, TRUE, status); 1.78 +} 1.79 + 1.80 +CompoundTransliterator::CompoundTransliterator(const UnicodeString& id, 1.81 + UParseError& /*parseError*/, 1.82 + UErrorCode& status) : 1.83 + Transliterator(id, 0), // set filter to 0 here! 1.84 + trans(0), numAnonymousRBTs(0) { 1.85 + // TODO add code for parseError...currently unused, but 1.86 + // later may be used by parsing code... 1.87 + init(id, UTRANS_FORWARD, TRUE, status); 1.88 +} 1.89 + 1.90 + 1.91 +/** 1.92 + * Private constructor for use of TransliteratorAlias 1.93 + */ 1.94 +CompoundTransliterator::CompoundTransliterator(const UnicodeString& newID, 1.95 + UVector& list, 1.96 + UnicodeFilter* adoptedFilter, 1.97 + int32_t anonymousRBTs, 1.98 + UParseError& /*parseError*/, 1.99 + UErrorCode& status) : 1.100 + Transliterator(newID, adoptedFilter), 1.101 + trans(0), numAnonymousRBTs(anonymousRBTs) 1.102 +{ 1.103 + init(list, UTRANS_FORWARD, FALSE, status); 1.104 +} 1.105 + 1.106 +/** 1.107 + * Private constructor for Transliterator from a vector of 1.108 + * transliterators. The caller is responsible for fixing up the 1.109 + * ID. 1.110 + */ 1.111 +CompoundTransliterator::CompoundTransliterator(UVector& list, 1.112 + UParseError& /*parseError*/, 1.113 + UErrorCode& status) : 1.114 + Transliterator(UnicodeString(), NULL), 1.115 + trans(0), numAnonymousRBTs(0) 1.116 +{ 1.117 + // TODO add code for parseError...currently unused, but 1.118 + // later may be used by parsing code... 1.119 + init(list, UTRANS_FORWARD, FALSE, status); 1.120 + // assume caller will fixup ID 1.121 +} 1.122 + 1.123 +CompoundTransliterator::CompoundTransliterator(UVector& list, 1.124 + int32_t anonymousRBTs, 1.125 + UParseError& /*parseError*/, 1.126 + UErrorCode& status) : 1.127 + Transliterator(UnicodeString(), NULL), 1.128 + trans(0), numAnonymousRBTs(anonymousRBTs) 1.129 +{ 1.130 + init(list, UTRANS_FORWARD, FALSE, status); 1.131 +} 1.132 + 1.133 +/** 1.134 + * Finish constructing a transliterator: only to be called by 1.135 + * constructors. Before calling init(), set trans and filter to NULL. 1.136 + * @param id the id containing ';'-separated entries 1.137 + * @param direction either FORWARD or REVERSE 1.138 + * @param idSplitPoint the index into id at which the 1.139 + * adoptedSplitTransliterator should be inserted, if there is one, or 1.140 + * -1 if there is none. 1.141 + * @param adoptedSplitTransliterator a transliterator to be inserted 1.142 + * before the entry at offset idSplitPoint in the id string. May be 1.143 + * NULL to insert no entry. 1.144 + * @param fixReverseID if TRUE, then reconstruct the ID of reverse 1.145 + * entries by calling getID() of component entries. Some constructors 1.146 + * do not require this because they apply a facade ID anyway. 1.147 + * @param status the error code indicating success or failure 1.148 + */ 1.149 +void CompoundTransliterator::init(const UnicodeString& id, 1.150 + UTransDirection direction, 1.151 + UBool fixReverseID, 1.152 + UErrorCode& status) { 1.153 + // assert(trans == 0); 1.154 + 1.155 + if (U_FAILURE(status)) { 1.156 + return; 1.157 + } 1.158 + 1.159 + UVector list(status); 1.160 + UnicodeSet* compoundFilter = NULL; 1.161 + UnicodeString regenID; 1.162 + if (!TransliteratorIDParser::parseCompoundID(id, direction, 1.163 + regenID, list, compoundFilter)) { 1.164 + status = U_INVALID_ID; 1.165 + delete compoundFilter; 1.166 + return; 1.167 + } 1.168 + 1.169 + TransliteratorIDParser::instantiateList(list, status); 1.170 + 1.171 + init(list, direction, fixReverseID, status); 1.172 + 1.173 + if (compoundFilter != NULL) { 1.174 + adoptFilter(compoundFilter); 1.175 + } 1.176 +} 1.177 + 1.178 +/** 1.179 + * Finish constructing a transliterator: only to be called by 1.180 + * constructors. Before calling init(), set trans and filter to NULL. 1.181 + * @param list a vector of transliterator objects to be adopted. It 1.182 + * should NOT be empty. The list should be in declared order. That 1.183 + * is, it should be in the FORWARD order; if direction is REVERSE then 1.184 + * the list order will be reversed. 1.185 + * @param direction either FORWARD or REVERSE 1.186 + * @param fixReverseID if TRUE, then reconstruct the ID of reverse 1.187 + * entries by calling getID() of component entries. Some constructors 1.188 + * do not require this because they apply a facade ID anyway. 1.189 + * @param status the error code indicating success or failure 1.190 + */ 1.191 +void CompoundTransliterator::init(UVector& list, 1.192 + UTransDirection direction, 1.193 + UBool fixReverseID, 1.194 + UErrorCode& status) { 1.195 + // assert(trans == 0); 1.196 + 1.197 + // Allocate array 1.198 + if (U_SUCCESS(status)) { 1.199 + count = list.size(); 1.200 + trans = (Transliterator **)uprv_malloc(count * sizeof(Transliterator *)); 1.201 + /* test for NULL */ 1.202 + if (trans == 0) { 1.203 + status = U_MEMORY_ALLOCATION_ERROR; 1.204 + return; 1.205 + } 1.206 + } 1.207 + 1.208 + if (U_FAILURE(status) || trans == 0) { 1.209 + // assert(trans == 0); 1.210 + return; 1.211 + } 1.212 + 1.213 + // Move the transliterators from the vector into an array. 1.214 + // Reverse the order if necessary. 1.215 + int32_t i; 1.216 + for (i=0; i<count; ++i) { 1.217 + int32_t j = (direction == UTRANS_FORWARD) ? i : count - 1 - i; 1.218 + trans[i] = (Transliterator*) list.elementAt(j); 1.219 + } 1.220 + 1.221 + // If the direction is UTRANS_REVERSE then we may need to fix the 1.222 + // ID. 1.223 + if (direction == UTRANS_REVERSE && fixReverseID) { 1.224 + UnicodeString newID; 1.225 + for (i=0; i<count; ++i) { 1.226 + if (i > 0) { 1.227 + newID.append(ID_DELIM); 1.228 + } 1.229 + newID.append(trans[i]->getID()); 1.230 + } 1.231 + setID(newID); 1.232 + } 1.233 + 1.234 + computeMaximumContextLength(); 1.235 +} 1.236 + 1.237 +/** 1.238 + * Return the IDs of the given list of transliterators, concatenated 1.239 + * with ID_DELIM delimiting them. Equivalent to the perlish expression 1.240 + * join(ID_DELIM, map($_.getID(), transliterators). 1.241 + */ 1.242 +UnicodeString CompoundTransliterator::joinIDs(Transliterator* const transliterators[], 1.243 + int32_t transCount) { 1.244 + UnicodeString id; 1.245 + for (int32_t i=0; i<transCount; ++i) { 1.246 + if (i > 0) { 1.247 + id.append(ID_DELIM); 1.248 + } 1.249 + id.append(transliterators[i]->getID()); 1.250 + } 1.251 + return id; // Return temporary 1.252 +} 1.253 + 1.254 +/** 1.255 + * Copy constructor. 1.256 + */ 1.257 +CompoundTransliterator::CompoundTransliterator(const CompoundTransliterator& t) : 1.258 + Transliterator(t), trans(0), count(0), numAnonymousRBTs(-1) { 1.259 + *this = t; 1.260 +} 1.261 + 1.262 +/** 1.263 + * Destructor 1.264 + */ 1.265 +CompoundTransliterator::~CompoundTransliterator() { 1.266 + freeTransliterators(); 1.267 +} 1.268 + 1.269 +void CompoundTransliterator::freeTransliterators(void) { 1.270 + if (trans != 0) { 1.271 + for (int32_t i=0; i<count; ++i) { 1.272 + delete trans[i]; 1.273 + } 1.274 + uprv_free(trans); 1.275 + } 1.276 + trans = 0; 1.277 + count = 0; 1.278 +} 1.279 + 1.280 +/** 1.281 + * Assignment operator. 1.282 + */ 1.283 +CompoundTransliterator& CompoundTransliterator::operator=( 1.284 + const CompoundTransliterator& t) 1.285 +{ 1.286 + Transliterator::operator=(t); 1.287 + int32_t i = 0; 1.288 + UBool failed = FALSE; 1.289 + if (trans != NULL) { 1.290 + for (i=0; i<count; ++i) { 1.291 + delete trans[i]; 1.292 + trans[i] = 0; 1.293 + } 1.294 + } 1.295 + if (t.count > count) { 1.296 + if (trans != NULL) { 1.297 + uprv_free(trans); 1.298 + } 1.299 + trans = (Transliterator **)uprv_malloc(t.count * sizeof(Transliterator *)); 1.300 + } 1.301 + count = t.count; 1.302 + if (trans != NULL) { 1.303 + for (i=0; i<count; ++i) { 1.304 + trans[i] = t.trans[i]->clone(); 1.305 + if (trans[i] == NULL) { 1.306 + failed = TRUE; 1.307 + break; 1.308 + } 1.309 + } 1.310 + } 1.311 + 1.312 + // if memory allocation failed delete backwards trans array 1.313 + if (failed && i > 0) { 1.314 + int32_t n; 1.315 + for (n = i-1; n >= 0; n--) { 1.316 + uprv_free(trans[n]); 1.317 + trans[n] = NULL; 1.318 + } 1.319 + } 1.320 + numAnonymousRBTs = t.numAnonymousRBTs; 1.321 + return *this; 1.322 +} 1.323 + 1.324 +/** 1.325 + * Transliterator API. 1.326 + */ 1.327 +Transliterator* CompoundTransliterator::clone(void) const { 1.328 + return new CompoundTransliterator(*this); 1.329 +} 1.330 + 1.331 +/** 1.332 + * Returns the number of transliterators in this chain. 1.333 + * @return number of transliterators in this chain. 1.334 + */ 1.335 +int32_t CompoundTransliterator::getCount(void) const { 1.336 + return count; 1.337 +} 1.338 + 1.339 +/** 1.340 + * Returns the transliterator at the given index in this chain. 1.341 + * @param index index into chain, from 0 to <code>getCount() - 1</code> 1.342 + * @return transliterator at the given index 1.343 + */ 1.344 +const Transliterator& CompoundTransliterator::getTransliterator(int32_t index) const { 1.345 + return *trans[index]; 1.346 +} 1.347 + 1.348 +void CompoundTransliterator::setTransliterators(Transliterator* const transliterators[], 1.349 + int32_t transCount) { 1.350 + Transliterator** a = (Transliterator **)uprv_malloc(transCount * sizeof(Transliterator *)); 1.351 + if (a == NULL) { 1.352 + return; 1.353 + } 1.354 + int32_t i = 0; 1.355 + UBool failed = FALSE; 1.356 + for (i=0; i<transCount; ++i) { 1.357 + a[i] = transliterators[i]->clone(); 1.358 + if (a[i] == NULL) { 1.359 + failed = TRUE; 1.360 + break; 1.361 + } 1.362 + } 1.363 + if (failed && i > 0) { 1.364 + int32_t n; 1.365 + for (n = i-1; n >= 0; n--) { 1.366 + uprv_free(a[n]); 1.367 + a[n] = NULL; 1.368 + } 1.369 + return; 1.370 + } 1.371 + adoptTransliterators(a, transCount); 1.372 +} 1.373 + 1.374 +void CompoundTransliterator::adoptTransliterators(Transliterator* adoptedTransliterators[], 1.375 + int32_t transCount) { 1.376 + // First free trans[] and set count to zero. Once this is done, 1.377 + // orphan the filter. Set up the new trans[]. 1.378 + freeTransliterators(); 1.379 + trans = adoptedTransliterators; 1.380 + count = transCount; 1.381 + computeMaximumContextLength(); 1.382 + setID(joinIDs(trans, count)); 1.383 +} 1.384 + 1.385 +/** 1.386 + * Append c to buf, unless buf is empty or buf already ends in c. 1.387 + */ 1.388 +static void _smartAppend(UnicodeString& buf, UChar c) { 1.389 + if (buf.length() != 0 && 1.390 + buf.charAt(buf.length() - 1) != c) { 1.391 + buf.append(c); 1.392 + } 1.393 +} 1.394 + 1.395 +UnicodeString& CompoundTransliterator::toRules(UnicodeString& rulesSource, 1.396 + UBool escapeUnprintable) const { 1.397 + // We do NOT call toRules() on our component transliterators, in 1.398 + // general. If we have several rule-based transliterators, this 1.399 + // yields a concatenation of the rules -- not what we want. We do 1.400 + // handle compound RBT transliterators specially -- those for which 1.401 + // compoundRBTIndex >= 0. For the transliterator at compoundRBTIndex, 1.402 + // we do call toRules() recursively. 1.403 + rulesSource.truncate(0); 1.404 + if (numAnonymousRBTs >= 1 && getFilter() != NULL) { 1.405 + // If we are a compound RBT and if we have a global 1.406 + // filter, then emit it at the top. 1.407 + UnicodeString pat; 1.408 + rulesSource.append(COLON_COLON, 2).append(getFilter()->toPattern(pat, escapeUnprintable)).append(ID_DELIM); 1.409 + } 1.410 + for (int32_t i=0; i<count; ++i) { 1.411 + UnicodeString rule; 1.412 + 1.413 + // Anonymous RuleBasedTransliterators (inline rules and 1.414 + // ::BEGIN/::END blocks) are given IDs that begin with 1.415 + // "%Pass": use toRules() to write all the rules to the output 1.416 + // (and insert "::Null;" if we have two in a row) 1.417 + if (trans[i]->getID().startsWith(PASS_STRING, 5)) { 1.418 + trans[i]->toRules(rule, escapeUnprintable); 1.419 + if (numAnonymousRBTs > 1 && i > 0 && trans[i - 1]->getID().startsWith(PASS_STRING, 5)) 1.420 + rule = UNICODE_STRING_SIMPLE("::Null;") + rule; 1.421 + 1.422 + // we also use toRules() on CompoundTransliterators (which we 1.423 + // check for by looking for a semicolon in the ID)-- this gets 1.424 + // the list of their child transliterators output in the right 1.425 + // format 1.426 + } else if (trans[i]->getID().indexOf(ID_DELIM) >= 0) { 1.427 + trans[i]->toRules(rule, escapeUnprintable); 1.428 + 1.429 + // for everything else, use Transliterator::toRules() 1.430 + } else { 1.431 + trans[i]->Transliterator::toRules(rule, escapeUnprintable); 1.432 + } 1.433 + _smartAppend(rulesSource, NEWLINE); 1.434 + rulesSource.append(rule); 1.435 + _smartAppend(rulesSource, ID_DELIM); 1.436 + } 1.437 + return rulesSource; 1.438 +} 1.439 + 1.440 +/** 1.441 + * Implement Transliterator framework 1.442 + */ 1.443 +void CompoundTransliterator::handleGetSourceSet(UnicodeSet& result) const { 1.444 + UnicodeSet set; 1.445 + result.clear(); 1.446 + for (int32_t i=0; i<count; ++i) { 1.447 + result.addAll(trans[i]->getSourceSet(set)); 1.448 + // Take the example of Hiragana-Latin. This is really 1.449 + // Hiragana-Katakana; Katakana-Latin. The source set of 1.450 + // these two is roughly [:Hiragana:] and [:Katakana:]. 1.451 + // But the source set for the entire transliterator is 1.452 + // actually [:Hiragana:] ONLY -- that is, the first 1.453 + // non-empty source set. 1.454 + 1.455 + // This is a heuristic, and not 100% reliable. 1.456 + if (!result.isEmpty()) { 1.457 + break; 1.458 + } 1.459 + } 1.460 +} 1.461 + 1.462 +/** 1.463 + * Override Transliterator framework 1.464 + */ 1.465 +UnicodeSet& CompoundTransliterator::getTargetSet(UnicodeSet& result) const { 1.466 + UnicodeSet set; 1.467 + result.clear(); 1.468 + for (int32_t i=0; i<count; ++i) { 1.469 + // This is a heuristic, and not 100% reliable. 1.470 + result.addAll(trans[i]->getTargetSet(set)); 1.471 + } 1.472 + return result; 1.473 +} 1.474 + 1.475 +/** 1.476 + * Implements {@link Transliterator#handleTransliterate}. 1.477 + */ 1.478 +void CompoundTransliterator::handleTransliterate(Replaceable& text, UTransPosition& index, 1.479 + UBool incremental) const { 1.480 + /* Call each transliterator with the same contextStart and 1.481 + * start, but with the limit as modified 1.482 + * by preceding transliterators. The start index must be 1.483 + * reset for each transliterator to give each a chance to 1.484 + * transliterate the text. The initial contextStart index is known 1.485 + * to still point to the same place after each transliterator 1.486 + * is called because each transliterator will not change the 1.487 + * text between contextStart and the initial start index. 1.488 + * 1.489 + * IMPORTANT: After the first transliterator, each subsequent 1.490 + * transliterator only gets to transliterate text committed by 1.491 + * preceding transliterators; that is, the start (output 1.492 + * value) of transliterator i becomes the limit (input value) 1.493 + * of transliterator i+1. Finally, the overall limit is fixed 1.494 + * up before we return. 1.495 + * 1.496 + * Assumptions we make here: 1.497 + * (1) contextStart <= start <= limit <= contextLimit <= text.length() 1.498 + * (2) start <= start' <= limit' ;cursor doesn't move back 1.499 + * (3) start <= limit' ;text before cursor unchanged 1.500 + * - start' is the value of start after calling handleKT 1.501 + * - limit' is the value of limit after calling handleKT 1.502 + */ 1.503 + 1.504 + /** 1.505 + * Example: 3 transliterators. This example illustrates the 1.506 + * mechanics we need to implement. C, S, and L are the contextStart, 1.507 + * start, and limit. gl is the globalLimit. contextLimit is 1.508 + * equal to limit throughout. 1.509 + * 1.510 + * 1. h-u, changes hex to Unicode 1.511 + * 1.512 + * 4 7 a d 0 4 7 a 1.513 + * abc/u0061/u => abca/u 1.514 + * C S L C S L gl=f->a 1.515 + * 1.516 + * 2. upup, changes "x" to "XX" 1.517 + * 1.518 + * 4 7 a 4 7 a 1.519 + * abca/u => abcAA/u 1.520 + * C SL C S 1.521 + * L gl=a->b 1.522 + * 3. u-h, changes Unicode to hex 1.523 + * 1.524 + * 4 7 a 4 7 a d 0 3 1.525 + * abcAA/u => abc/u0041/u0041/u 1.526 + * C S L C S 1.527 + * L gl=b->15 1.528 + * 4. return 1.529 + * 1.530 + * 4 7 a d 0 3 1.531 + * abc/u0041/u0041/u 1.532 + * C S L 1.533 + */ 1.534 + 1.535 + if (count < 1) { 1.536 + index.start = index.limit; 1.537 + return; // Short circuit for empty compound transliterators 1.538 + } 1.539 + 1.540 + // compoundLimit is the limit value for the entire compound 1.541 + // operation. We overwrite index.limit with the previous 1.542 + // index.start. After each transliteration, we update 1.543 + // compoundLimit for insertions or deletions that have happened. 1.544 + int32_t compoundLimit = index.limit; 1.545 + 1.546 + // compoundStart is the start for the entire compound 1.547 + // operation. 1.548 + int32_t compoundStart = index.start; 1.549 + 1.550 + int32_t delta = 0; // delta in length 1.551 + 1.552 + // Give each transliterator a crack at the run of characters. 1.553 + // See comments at the top of the method for more detail. 1.554 + for (int32_t i=0; i<count; ++i) { 1.555 + index.start = compoundStart; // Reset start 1.556 + int32_t limit = index.limit; 1.557 + 1.558 + if (index.start == index.limit) { 1.559 + // Short circuit for empty range 1.560 + break; 1.561 + } 1.562 + 1.563 + trans[i]->filteredTransliterate(text, index, incremental); 1.564 + 1.565 + // In a properly written transliterator, start == limit after 1.566 + // handleTransliterate() returns when incremental is false. 1.567 + // Catch cases where the subclass doesn't do this, and throw 1.568 + // an exception. (Just pinning start to limit is a bad idea, 1.569 + // because what's probably happening is that the subclass 1.570 + // isn't transliterating all the way to the end, and it should 1.571 + // in non-incremental mode.) 1.572 + if (!incremental && index.start != index.limit) { 1.573 + // We can't throw an exception, so just fudge things 1.574 + index.start = index.limit; 1.575 + } 1.576 + 1.577 + // Cumulative delta for insertions/deletions 1.578 + delta += index.limit - limit; 1.579 + 1.580 + if (incremental) { 1.581 + // In the incremental case, only allow subsequent 1.582 + // transliterators to modify what has already been 1.583 + // completely processed by prior transliterators. In the 1.584 + // non-incrmental case, allow each transliterator to 1.585 + // process the entire text. 1.586 + index.limit = index.start; 1.587 + } 1.588 + } 1.589 + 1.590 + compoundLimit += delta; 1.591 + 1.592 + // Start is good where it is -- where the last transliterator left 1.593 + // it. Limit needs to be put back where it was, modulo 1.594 + // adjustments for deletions/insertions. 1.595 + index.limit = compoundLimit; 1.596 +} 1.597 + 1.598 +/** 1.599 + * Sets the length of the longest context required by this transliterator. 1.600 + * This is <em>preceding</em> context. 1.601 + */ 1.602 +void CompoundTransliterator::computeMaximumContextLength(void) { 1.603 + int32_t max = 0; 1.604 + for (int32_t i=0; i<count; ++i) { 1.605 + int32_t len = trans[i]->getMaximumContextLength(); 1.606 + if (len > max) { 1.607 + max = len; 1.608 + } 1.609 + } 1.610 + setMaximumContextLength(max); 1.611 +} 1.612 + 1.613 +U_NAMESPACE_END 1.614 + 1.615 +#endif /* #if !UCONFIG_NO_TRANSLITERATION */ 1.616 + 1.617 +/* eof */