1 // Copyright (C) 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4 ***************************************************************************
5 *   Copyright (C) 1999-2016 International Business Machines Corporation
6 *   and others. All rights reserved.
7 ***************************************************************************
8 */
9 //
10 //  file:  rbbi.c    Contains the implementation of the rule based break iterator
11 //                   runtime engine and the API implementation for
12 //                   class RuleBasedBreakIterator
13 //
14 
15 #include "utypeinfo.h"  // for 'typeid' to work
16 
17 #include "unicode/utypes.h"
18 
19 #if !UCONFIG_NO_BREAK_ITERATION
20 
21 #include "unicode/rbbi.h"
22 #include "unicode/schriter.h"
23 #include "unicode/uchriter.h"
24 #include "unicode/udata.h"
25 #include "unicode/uclean.h"
26 #include "rbbidata.h"
27 #include "rbbirb.h"
28 #include "cmemory.h"
29 #include "cstring.h"
30 #include "umutex.h"
31 #include "ucln_cmn.h"
32 #include "brkeng.h"
33 
34 #include "uassert.h"
35 #include "uvector.h"
36 
37 // if U_LOCAL_SERVICE_HOOK is defined, then localsvc.cpp is expected to be included.
38 #if U_LOCAL_SERVICE_HOOK
39 #include "localsvc.h"
40 #endif
41 
42 #ifdef RBBI_DEBUG
43 static UBool fTrace = FALSE;
44 #endif
45 
46 U_NAMESPACE_BEGIN
47 
48 // The state number of the starting state
49 #define START_STATE 1
50 
51 // The state-transition value indicating "stop"
52 #define STOP_STATE  0
53 
54 
UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedBreakIterator)55 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedBreakIterator)
56 
57 
58 //=======================================================================
59 // constructors
60 //=======================================================================
61 
62 /**
63  * Constructs a RuleBasedBreakIterator that uses the already-created
64  * tables object that is passed in as a parameter.
65  */
66 RuleBasedBreakIterator::RuleBasedBreakIterator(RBBIDataHeader* data, UErrorCode &status)
67 {
68     init();
69     fData = new RBBIDataWrapper(data, status); // status checked in constructor
70     if (U_FAILURE(status)) {return;}
71     if(fData == 0) {
72         status = U_MEMORY_ALLOCATION_ERROR;
73         return;
74     }
75 }
76 
77 //
78 //  Construct from precompiled binary rules (tables).  This constructor is public API,
79 //  taking the rules as a (const uint8_t *) to match the type produced by getBinaryRules().
80 //
RuleBasedBreakIterator(const uint8_t * compiledRules,uint32_t ruleLength,UErrorCode & status)81 RuleBasedBreakIterator::RuleBasedBreakIterator(const uint8_t *compiledRules,
82                        uint32_t       ruleLength,
83                        UErrorCode     &status) {
84     init();
85     if (U_FAILURE(status)) {
86         return;
87     }
88     if (compiledRules == NULL || ruleLength < sizeof(RBBIDataHeader)) {
89         status = U_ILLEGAL_ARGUMENT_ERROR;
90         return;
91     }
92     const RBBIDataHeader *data = (const RBBIDataHeader *)compiledRules;
93     if (data->fLength > ruleLength) {
94         status = U_ILLEGAL_ARGUMENT_ERROR;
95         return;
96     }
97     fData = new RBBIDataWrapper(data, RBBIDataWrapper::kDontAdopt, status);
98     if (U_FAILURE(status)) {return;}
99     if(fData == 0) {
100         status = U_MEMORY_ALLOCATION_ERROR;
101         return;
102     }
103 }
104 
105 
106 //-------------------------------------------------------------------------------
107 //
108 //   Constructor   from a UDataMemory handle to precompiled break rules
109 //                 stored in an ICU data file.
110 //
111 //-------------------------------------------------------------------------------
RuleBasedBreakIterator(UDataMemory * udm,UErrorCode & status)112 RuleBasedBreakIterator::RuleBasedBreakIterator(UDataMemory* udm, UErrorCode &status)
113 {
114     init();
115     fData = new RBBIDataWrapper(udm, status); // status checked in constructor
116     if (U_FAILURE(status)) {return;}
117     if(fData == 0) {
118         status = U_MEMORY_ALLOCATION_ERROR;
119         return;
120     }
121 }
122 
123 
124 
125 //-------------------------------------------------------------------------------
126 //
127 //   Constructor       from a set of rules supplied as a string.
128 //
129 //-------------------------------------------------------------------------------
RuleBasedBreakIterator(const UnicodeString & rules,UParseError & parseError,UErrorCode & status)130 RuleBasedBreakIterator::RuleBasedBreakIterator( const UnicodeString  &rules,
131                                                 UParseError          &parseError,
132                                                 UErrorCode           &status)
133 {
134     init();
135     if (U_FAILURE(status)) {return;}
136     RuleBasedBreakIterator *bi = (RuleBasedBreakIterator *)
137         RBBIRuleBuilder::createRuleBasedBreakIterator(rules, &parseError, status);
138     // Note:  This is a bit awkward.  The RBBI ruleBuilder has a factory method that
139     //        creates and returns a complete RBBI.  From here, in a constructor, we
140     //        can't just return the object created by the builder factory, hence
141     //        the assignment of the factory created object to "this".
142     if (U_SUCCESS(status)) {
143         *this = *bi;
144         delete bi;
145     }
146 }
147 
148 
149 //-------------------------------------------------------------------------------
150 //
151 // Default Constructor.      Create an empty shell that can be set up later.
152 //                           Used when creating a RuleBasedBreakIterator from a set
153 //                           of rules.
154 //-------------------------------------------------------------------------------
RuleBasedBreakIterator()155 RuleBasedBreakIterator::RuleBasedBreakIterator() {
156     init();
157 }
158 
159 
160 //-------------------------------------------------------------------------------
161 //
162 //   Copy constructor.  Will produce a break iterator with the same behavior,
163 //                      and which iterates over the same text, as the one passed in.
164 //
165 //-------------------------------------------------------------------------------
RuleBasedBreakIterator(const RuleBasedBreakIterator & other)166 RuleBasedBreakIterator::RuleBasedBreakIterator(const RuleBasedBreakIterator& other)
167 : BreakIterator(other)
168 {
169     this->init();
170     *this = other;
171 }
172 
173 
174 /**
175  * Destructor
176  */
~RuleBasedBreakIterator()177 RuleBasedBreakIterator::~RuleBasedBreakIterator() {
178     if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
179         // fCharIter was adopted from the outside.
180         delete fCharIter;
181     }
182     fCharIter = NULL;
183     delete fSCharIter;
184     fCharIter = NULL;
185     delete fDCharIter;
186     fDCharIter = NULL;
187 
188     utext_close(fText);
189 
190     if (fData != NULL) {
191         fData->removeReference();
192         fData = NULL;
193     }
194     if (fCachedBreakPositions) {
195         uprv_free(fCachedBreakPositions);
196         fCachedBreakPositions = NULL;
197     }
198     if (fLanguageBreakEngines) {
199         delete fLanguageBreakEngines;
200         fLanguageBreakEngines = NULL;
201     }
202     if (fUnhandledBreakEngine) {
203         delete fUnhandledBreakEngine;
204         fUnhandledBreakEngine = NULL;
205     }
206 }
207 
208 /**
209  * Assignment operator.  Sets this iterator to have the same behavior,
210  * and iterate over the same text, as the one passed in.
211  */
212 RuleBasedBreakIterator&
operator =(const RuleBasedBreakIterator & that)213 RuleBasedBreakIterator::operator=(const RuleBasedBreakIterator& that) {
214     if (this == &that) {
215         return *this;
216     }
217     reset();    // Delete break cache information
218     fBreakType = that.fBreakType;
219     if (fLanguageBreakEngines != NULL) {
220         delete fLanguageBreakEngines;
221         fLanguageBreakEngines = NULL;   // Just rebuild for now
222     }
223     // TODO: clone fLanguageBreakEngines from "that"
224     UErrorCode status = U_ZERO_ERROR;
225     fText = utext_clone(fText, that.fText, FALSE, TRUE, &status);
226 
227     if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
228         delete fCharIter;
229     }
230     fCharIter = NULL;
231 
232     if (that.fCharIter != NULL ) {
233         // This is a little bit tricky - it will intially appear that
234         //  this->fCharIter is adopted, even if that->fCharIter was
235         //  not adopted.  That's ok.
236         fCharIter = that.fCharIter->clone();
237     }
238 
239     if (fData != NULL) {
240         fData->removeReference();
241         fData = NULL;
242     }
243     if (that.fData != NULL) {
244         fData = that.fData->addReference();
245     }
246 
247     return *this;
248 }
249 
250 
251 
252 //-----------------------------------------------------------------------------
253 //
254 //    init()      Shared initialization routine.   Used by all the constructors.
255 //                Initializes all fields, leaving the object in a consistent state.
256 //
257 //-----------------------------------------------------------------------------
init()258 void RuleBasedBreakIterator::init() {
259     UErrorCode  status    = U_ZERO_ERROR;
260     fText                 = utext_openUChars(NULL, NULL, 0, &status);
261     fCharIter             = NULL;
262     fSCharIter            = NULL;
263     fDCharIter            = NULL;
264     fData                 = NULL;
265     fLastRuleStatusIndex  = 0;
266     fLastStatusIndexValid = TRUE;
267     fDictionaryCharCount  = 0;
268     fBreakType            = UBRK_WORD;  // Defaulting BreakType to word gives reasonable
269                                         //   dictionary behavior for Break Iterators that are
270                                         //   built from rules.  Even better would be the ability to
271                                         //   declare the type in the rules.
272 
273     fCachedBreakPositions    = NULL;
274     fLanguageBreakEngines    = NULL;
275     fUnhandledBreakEngine    = NULL;
276     fNumCachedBreakPositions = 0;
277     fPositionInCache         = 0;
278 
279 #ifdef RBBI_DEBUG
280     static UBool debugInitDone = FALSE;
281     if (debugInitDone == FALSE) {
282         char *debugEnv = getenv("U_RBBIDEBUG");
283         if (debugEnv && uprv_strstr(debugEnv, "trace")) {
284             fTrace = TRUE;
285         }
286         debugInitDone = TRUE;
287     }
288 #endif
289 }
290 
291 
292 
293 //-----------------------------------------------------------------------------
294 //
295 //    clone - Returns a newly-constructed RuleBasedBreakIterator with the same
296 //            behavior, and iterating over the same text, as this one.
297 //            Virtual function: does the right thing with subclasses.
298 //
299 //-----------------------------------------------------------------------------
300 BreakIterator*
clone(void) const301 RuleBasedBreakIterator::clone(void) const {
302     return new RuleBasedBreakIterator(*this);
303 }
304 
305 /**
306  * Equality operator.  Returns TRUE if both BreakIterators are of the
307  * same class, have the same behavior, and iterate over the same text.
308  */
309 UBool
operator ==(const BreakIterator & that) const310 RuleBasedBreakIterator::operator==(const BreakIterator& that) const {
311     if (typeid(*this) != typeid(that)) {
312         return FALSE;
313     }
314 
315     const RuleBasedBreakIterator& that2 = (const RuleBasedBreakIterator&) that;
316 
317     if (!utext_equals(fText, that2.fText)) {
318         // The two break iterators are operating on different text,
319         //   or have a different interation position.
320         return FALSE;
321     };
322 
323     // TODO:  need a check for when in a dictionary region at different offsets.
324 
325     if (that2.fData == fData ||
326         (fData != NULL && that2.fData != NULL && *that2.fData == *fData)) {
327             // The two break iterators are using the same rules.
328             return TRUE;
329         }
330     return FALSE;
331 }
332 
333 /**
334  * Compute a hash code for this BreakIterator
335  * @return A hash code
336  */
337 int32_t
hashCode(void) const338 RuleBasedBreakIterator::hashCode(void) const {
339     int32_t   hash = 0;
340     if (fData != NULL) {
341         hash = fData->hashCode();
342     }
343     return hash;
344 }
345 
346 
setText(UText * ut,UErrorCode & status)347 void RuleBasedBreakIterator::setText(UText *ut, UErrorCode &status) {
348     if (U_FAILURE(status)) {
349         return;
350     }
351     reset();
352     fText = utext_clone(fText, ut, FALSE, TRUE, &status);
353 
354     // Set up a dummy CharacterIterator to be returned if anyone
355     //   calls getText().  With input from UText, there is no reasonable
356     //   way to return a characterIterator over the actual input text.
357     //   Return one over an empty string instead - this is the closest
358     //   we can come to signaling a failure.
359     //   (GetText() is obsolete, this failure is sort of OK)
360     if (fDCharIter == NULL) {
361         static const UChar c = 0;
362         fDCharIter = new UCharCharacterIterator(&c, 0);
363         if (fDCharIter == NULL) {
364             status = U_MEMORY_ALLOCATION_ERROR;
365             return;
366         }
367     }
368 
369     if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
370         // existing fCharIter was adopted from the outside.  Delete it now.
371         delete fCharIter;
372     }
373     fCharIter = fDCharIter;
374 
375     this->first();
376 }
377 
378 
getUText(UText * fillIn,UErrorCode & status) const379 UText *RuleBasedBreakIterator::getUText(UText *fillIn, UErrorCode &status) const {
380     UText *result = utext_clone(fillIn, fText, FALSE, TRUE, &status);
381     return result;
382 }
383 
384 
385 
386 /**
387  * Returns the description used to create this iterator
388  */
389 const UnicodeString&
getRules() const390 RuleBasedBreakIterator::getRules() const {
391     if (fData != NULL) {
392         return fData->getRuleSourceString();
393     } else {
394         static const UnicodeString *s;
395         if (s == NULL) {
396             // TODO:  something more elegant here.
397             //        perhaps API should return the string by value.
398             //        Note:  thread unsafe init & leak are semi-ok, better than
399             //               what was before.  Sould be cleaned up, though.
400             s = new UnicodeString;
401         }
402         return *s;
403     }
404 }
405 
406 //=======================================================================
407 // BreakIterator overrides
408 //=======================================================================
409 
410 /**
411  * Return a CharacterIterator over the text being analyzed.
412  */
413 CharacterIterator&
getText() const414 RuleBasedBreakIterator::getText() const {
415     return *fCharIter;
416 }
417 
418 /**
419  * Set the iterator to analyze a new piece of text.  This function resets
420  * the current iteration position to the beginning of the text.
421  * @param newText An iterator over the text to analyze.
422  */
423 void
adoptText(CharacterIterator * newText)424 RuleBasedBreakIterator::adoptText(CharacterIterator* newText) {
425     // If we are holding a CharacterIterator adopted from a
426     //   previous call to this function, delete it now.
427     if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
428         delete fCharIter;
429     }
430 
431     fCharIter = newText;
432     UErrorCode status = U_ZERO_ERROR;
433     reset();
434     if (newText==NULL || newText->startIndex() != 0) {
435         // startIndex !=0 wants to be an error, but there's no way to report it.
436         // Make the iterator text be an empty string.
437         fText = utext_openUChars(fText, NULL, 0, &status);
438     } else {
439         fText = utext_openCharacterIterator(fText, newText, &status);
440     }
441     this->first();
442 }
443 
444 /**
445  * Set the iterator to analyze a new piece of text.  This function resets
446  * the current iteration position to the beginning of the text.
447  * @param newText An iterator over the text to analyze.
448  */
449 void
setText(const UnicodeString & newText)450 RuleBasedBreakIterator::setText(const UnicodeString& newText) {
451     UErrorCode status = U_ZERO_ERROR;
452     reset();
453     fText = utext_openConstUnicodeString(fText, &newText, &status);
454 
455     // Set up a character iterator on the string.
456     //   Needed in case someone calls getText().
457     //  Can not, unfortunately, do this lazily on the (probably never)
458     //  call to getText(), because getText is const.
459     if (fSCharIter == NULL) {
460         fSCharIter = new StringCharacterIterator(newText);
461     } else {
462         fSCharIter->setText(newText);
463     }
464 
465     if (fCharIter!=fSCharIter && fCharIter!=fDCharIter) {
466         // old fCharIter was adopted from the outside.  Delete it.
467         delete fCharIter;
468     }
469     fCharIter = fSCharIter;
470 
471     this->first();
472 }
473 
474 
475 /**
476  *  Provide a new UText for the input text.  Must reference text with contents identical
477  *  to the original.
478  *  Intended for use with text data originating in Java (garbage collected) environments
479  *  where the data may be moved in memory at arbitrary times.
480  */
refreshInputText(UText * input,UErrorCode & status)481 RuleBasedBreakIterator &RuleBasedBreakIterator::refreshInputText(UText *input, UErrorCode &status) {
482     if (U_FAILURE(status)) {
483         return *this;
484     }
485     if (input == NULL) {
486         status = U_ILLEGAL_ARGUMENT_ERROR;
487         return *this;
488     }
489     int64_t pos = utext_getNativeIndex(fText);
490     //  Shallow read-only clone of the new UText into the existing input UText
491     fText = utext_clone(fText, input, FALSE, TRUE, &status);
492     if (U_FAILURE(status)) {
493         return *this;
494     }
495     utext_setNativeIndex(fText, pos);
496     if (utext_getNativeIndex(fText) != pos) {
497         // Sanity check.  The new input utext is supposed to have the exact same
498         // contents as the old.  If we can't set to the same position, it doesn't.
499         // The contents underlying the old utext might be invalid at this point,
500         // so it's not safe to check directly.
501         status = U_ILLEGAL_ARGUMENT_ERROR;
502     }
503     return *this;
504 }
505 
506 
507 /**
508  * Sets the current iteration position to the beginning of the text, position zero.
509  * @return The new iterator position, which is zero.
510  */
first(void)511 int32_t RuleBasedBreakIterator::first(void) {
512     reset();
513     fLastRuleStatusIndex  = 0;
514     fLastStatusIndexValid = TRUE;
515     //if (fText == NULL)
516     //    return BreakIterator::DONE;
517 
518     utext_setNativeIndex(fText, 0);
519     return 0;
520 }
521 
522 /**
523  * Sets the current iteration position to the end of the text.
524  * @return The text's past-the-end offset.
525  */
last(void)526 int32_t RuleBasedBreakIterator::last(void) {
527     reset();
528     if (fText == NULL) {
529         fLastRuleStatusIndex  = 0;
530         fLastStatusIndexValid = TRUE;
531         return BreakIterator::DONE;
532     }
533 
534     fLastStatusIndexValid = FALSE;
535     int32_t pos = (int32_t)utext_nativeLength(fText);
536     utext_setNativeIndex(fText, pos);
537     return pos;
538 }
539 
540 /**
541  * Advances the iterator either forward or backward the specified number of steps.
542  * Negative values move backward, and positive values move forward.  This is
543  * equivalent to repeatedly calling next() or previous().
544  * @param n The number of steps to move.  The sign indicates the direction
545  * (negative is backwards, and positive is forwards).
546  * @return The character offset of the boundary position n boundaries away from
547  * the current one.
548  */
next(int32_t n)549 int32_t RuleBasedBreakIterator::next(int32_t n) {
550     int32_t result = current();
551     while (n > 0) {
552         result = next();
553         --n;
554     }
555     while (n < 0) {
556         result = previous();
557         ++n;
558     }
559     return result;
560 }
561 
562 /**
563  * Advances the iterator to the next boundary position.
564  * @return The position of the first boundary after this one.
565  */
next(void)566 int32_t RuleBasedBreakIterator::next(void) {
567     // if we have cached break positions and we're still in the range
568     // covered by them, just move one step forward in the cache
569     if (fCachedBreakPositions != NULL) {
570         if (fPositionInCache < fNumCachedBreakPositions - 1) {
571             ++fPositionInCache;
572             int32_t pos = fCachedBreakPositions[fPositionInCache];
573             utext_setNativeIndex(fText, pos);
574             return pos;
575         }
576         else {
577             reset();
578         }
579     }
580 
581     int32_t startPos = current();
582     fDictionaryCharCount = 0;
583     int32_t result = handleNext(fData->fForwardTable);
584     if (fDictionaryCharCount > 0) {
585         result = checkDictionary(startPos, result, FALSE);
586     }
587     return result;
588 }
589 
590 /**
591  * Advances the iterator backwards, to the last boundary preceding this one.
592  * @return The position of the last boundary position preceding this one.
593  */
previous(void)594 int32_t RuleBasedBreakIterator::previous(void) {
595     int32_t result;
596     int32_t startPos;
597 
598     // if we have cached break positions and we're still in the range
599     // covered by them, just move one step backward in the cache
600     if (fCachedBreakPositions != NULL) {
601         if (fPositionInCache > 0) {
602             --fPositionInCache;
603             // If we're at the beginning of the cache, need to reevaluate the
604             // rule status
605             if (fPositionInCache <= 0) {
606                 fLastStatusIndexValid = FALSE;
607             }
608             int32_t pos = fCachedBreakPositions[fPositionInCache];
609             utext_setNativeIndex(fText, pos);
610             return pos;
611         }
612         else {
613             reset();
614         }
615     }
616 
617     // if we're already sitting at the beginning of the text, return DONE
618     if (fText == NULL || (startPos = current()) == 0) {
619         fLastRuleStatusIndex  = 0;
620         fLastStatusIndexValid = TRUE;
621         return BreakIterator::DONE;
622     }
623 
624     if (fData->fSafeRevTable != NULL || fData->fSafeFwdTable != NULL) {
625         result = handlePrevious(fData->fReverseTable);
626         if (fDictionaryCharCount > 0) {
627             result = checkDictionary(result, startPos, TRUE);
628         }
629         return result;
630     }
631 
632     // old rule syntax
633     // set things up.  handlePrevious() will back us up to some valid
634     // break position before the current position (we back our internal
635     // iterator up one step to prevent handlePrevious() from returning
636     // the current position), but not necessarily the last one before
637     // where we started
638 
639     int32_t start = current();
640 
641     (void)UTEXT_PREVIOUS32(fText);
642     int32_t lastResult    = handlePrevious(fData->fReverseTable);
643     if (lastResult == UBRK_DONE) {
644         lastResult = 0;
645         utext_setNativeIndex(fText, 0);
646     }
647     result = lastResult;
648     int32_t lastTag       = 0;
649     UBool   breakTagValid = FALSE;
650 
651     // iterate forward from the known break position until we pass our
652     // starting point.  The last break position before the starting
653     // point is our return value
654 
655     for (;;) {
656         result         = next();
657         if (result == BreakIterator::DONE || result >= start) {
658             break;
659         }
660         lastResult     = result;
661         lastTag        = fLastRuleStatusIndex;
662         breakTagValid  = TRUE;
663     }
664 
665     // fLastBreakTag wants to have the value for section of text preceding
666     // the result position that we are to return (in lastResult.)  If
667     // the backwards rules overshot and the above loop had to do two or more
668     // next()s to move up to the desired return position, we will have a valid
669     // tag value. But, if handlePrevious() took us to exactly the correct result position,
670     // we wont have a tag value for that position, which is only set by handleNext().
671 
672     // Set the current iteration position to be the last break position
673     // before where we started, and then return that value.
674     utext_setNativeIndex(fText, lastResult);
675     fLastRuleStatusIndex  = lastTag;       // for use by getRuleStatus()
676     fLastStatusIndexValid = breakTagValid;
677 
678     // No need to check the dictionary; it will have been handled by
679     // next()
680 
681     return lastResult;
682 }
683 
684 /**
685  * Sets the iterator to refer to the first boundary position following
686  * the specified position.
687  * @offset The position from which to begin searching for a break position.
688  * @return The position of the first break after the current position.
689  */
following(int32_t offset)690 int32_t RuleBasedBreakIterator::following(int32_t offset) {
691     // if the offset passed in is already past the end of the text,
692     // just return DONE; if it's before the beginning, return the
693     // text's starting offset
694     if (fText == NULL || offset >= utext_nativeLength(fText)) {
695         last();
696         return next();
697     }
698     else if (offset < 0) {
699         return first();
700     }
701 
702     // Move requested offset to a code point start. It might be on a trail surrogate,
703     // or on a trail byte if the input is UTF-8.
704     utext_setNativeIndex(fText, offset);
705     offset = (int32_t)utext_getNativeIndex(fText);
706 
707     // if we have cached break positions and offset is in the range
708     // covered by them, use them
709     // TODO: could use binary search
710     // TODO: what if offset is outside range, but break is not?
711     if (fCachedBreakPositions != NULL) {
712         if (offset >= fCachedBreakPositions[0]
713                 && offset < fCachedBreakPositions[fNumCachedBreakPositions - 1]) {
714             fPositionInCache = 0;
715             // We are guaranteed not to leave the array due to range test above
716             while (offset >= fCachedBreakPositions[fPositionInCache]) {
717                 ++fPositionInCache;
718             }
719             int32_t pos = fCachedBreakPositions[fPositionInCache];
720             utext_setNativeIndex(fText, pos);
721             return pos;
722         }
723         else {
724             reset();
725         }
726     }
727 
728     // Set our internal iteration position (temporarily)
729     // to the position passed in.  If this is the _beginning_ position,
730     // then we can just use next() to get our return value
731 
732     int32_t result = 0;
733 
734     if (fData->fSafeRevTable != NULL) {
735         // new rule syntax
736         utext_setNativeIndex(fText, offset);
737         // move forward one codepoint to prepare for moving back to a
738         // safe point.
739         // this handles offset being between a supplementary character
740         // TODO: is this still needed, with move to code point boundary handled above?
741         (void)UTEXT_NEXT32(fText);
742         // handlePrevious will move most of the time to < 1 boundary away
743         handlePrevious(fData->fSafeRevTable);
744         int32_t result = next();
745         while (result <= offset) {
746             result = next();
747         }
748         return result;
749     }
750     if (fData->fSafeFwdTable != NULL) {
751         // backup plan if forward safe table is not available
752         utext_setNativeIndex(fText, offset);
753         (void)UTEXT_PREVIOUS32(fText);
754         // handle next will give result >= offset
755         handleNext(fData->fSafeFwdTable);
756         // previous will give result 0 or 1 boundary away from offset,
757         // most of the time
758         // we have to
759         int32_t oldresult = previous();
760         while (oldresult > offset) {
761             int32_t result = previous();
762             if (result <= offset) {
763                 return oldresult;
764             }
765             oldresult = result;
766         }
767         int32_t result = next();
768         if (result <= offset) {
769             return next();
770         }
771         return result;
772     }
773     // otherwise, we have to sync up first.  Use handlePrevious() to back
774     // up to a known break position before the specified position (if
775     // we can determine that the specified position is a break position,
776     // we don't back up at all).  This may or may not be the last break
777     // position at or before our starting position.  Advance forward
778     // from here until we've passed the starting position.  The position
779     // we stop on will be the first break position after the specified one.
780     // old rule syntax
781 
782     utext_setNativeIndex(fText, offset);
783     if (offset==0 ||
784         (offset==1  && utext_getNativeIndex(fText)==0)) {
785         return next();
786     }
787     result = previous();
788 
789     while (result != BreakIterator::DONE && result <= offset) {
790         result = next();
791     }
792 
793     return result;
794 }
795 
796 /**
797  * Sets the iterator to refer to the last boundary position before the
798  * specified position.
799  * @offset The position to begin searching for a break from.
800  * @return The position of the last boundary before the starting position.
801  */
preceding(int32_t offset)802 int32_t RuleBasedBreakIterator::preceding(int32_t offset) {
803     // if the offset passed in is already past the end of the text,
804     // just return DONE; if it's before the beginning, return the
805     // text's starting offset
806     if (fText == NULL || offset > utext_nativeLength(fText)) {
807         return last();
808     }
809     else if (offset < 0) {
810         return first();
811     }
812 
813     // Move requested offset to a code point start. It might be on a trail surrogate,
814     // or on a trail byte if the input is UTF-8.
815     utext_setNativeIndex(fText, offset);
816     offset = (int32_t)utext_getNativeIndex(fText);
817 
818     // if we have cached break positions and offset is in the range
819     // covered by them, use them
820     if (fCachedBreakPositions != NULL) {
821         // TODO: binary search?
822         // TODO: What if offset is outside range, but break is not?
823         if (offset > fCachedBreakPositions[0]
824                 && offset <= fCachedBreakPositions[fNumCachedBreakPositions - 1]) {
825             fPositionInCache = 0;
826             while (fPositionInCache < fNumCachedBreakPositions
827                    && offset > fCachedBreakPositions[fPositionInCache])
828                 ++fPositionInCache;
829             --fPositionInCache;
830             // If we're at the beginning of the cache, need to reevaluate the
831             // rule status
832             if (fPositionInCache <= 0) {
833                 fLastStatusIndexValid = FALSE;
834             }
835             utext_setNativeIndex(fText, fCachedBreakPositions[fPositionInCache]);
836             return fCachedBreakPositions[fPositionInCache];
837         }
838         else {
839             reset();
840         }
841     }
842 
843     // if we start by updating the current iteration position to the
844     // position specified by the caller, we can just use previous()
845     // to carry out this operation
846 
847     if (fData->fSafeFwdTable != NULL) {
848         // new rule syntax
849         utext_setNativeIndex(fText, offset);
850         int32_t newOffset = (int32_t)UTEXT_GETNATIVEINDEX(fText);
851         if (newOffset != offset) {
852             // Will come here if specified offset was not a code point boundary AND
853             //   the underlying implmentation is using UText, which snaps any non-code-point-boundary
854             //   indices to the containing code point.
855             // For breakitereator::preceding only, these non-code-point indices need to be moved
856             //   up to refer to the following codepoint.
857             (void)UTEXT_NEXT32(fText);
858             offset = (int32_t)UTEXT_GETNATIVEINDEX(fText);
859         }
860 
861         // TODO:  (synwee) would it be better to just check for being in the middle of a surrogate pair,
862         //        rather than adjusting the position unconditionally?
863         //        (Change would interact with safe rules.)
864         // TODO:  change RBBI behavior for off-boundary indices to match that of UText?
865         //        affects only preceding(), seems cleaner, but is slightly different.
866         (void)UTEXT_PREVIOUS32(fText);
867         handleNext(fData->fSafeFwdTable);
868         int32_t result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
869         while (result >= offset) {
870             result = previous();
871         }
872         return result;
873     }
874     if (fData->fSafeRevTable != NULL) {
875         // backup plan if forward safe table is not available
876         //  TODO:  check whether this path can be discarded
877         //         It's probably OK to say that rules must supply both safe tables
878         //            if they use safe tables at all.  We have certainly never described
879         //            to anyone how to work with just one safe table.
880         utext_setNativeIndex(fText, offset);
881         (void)UTEXT_NEXT32(fText);
882 
883         // handle previous will give result <= offset
884         handlePrevious(fData->fSafeRevTable);
885 
886         // next will give result 0 or 1 boundary away from offset,
887         // most of the time
888         // we have to
889         int32_t oldresult = next();
890         while (oldresult < offset) {
891             int32_t result = next();
892             if (result >= offset) {
893                 return oldresult;
894             }
895             oldresult = result;
896         }
897         int32_t result = previous();
898         if (result >= offset) {
899             return previous();
900         }
901         return result;
902     }
903 
904     // old rule syntax
905     utext_setNativeIndex(fText, offset);
906     return previous();
907 }
908 
909 /**
910  * Returns true if the specfied position is a boundary position.  As a side
911  * effect, leaves the iterator pointing to the first boundary position at
912  * or after "offset".
913  * @param offset the offset to check.
914  * @return True if "offset" is a boundary position.
915  */
isBoundary(int32_t offset)916 UBool RuleBasedBreakIterator::isBoundary(int32_t offset) {
917     // the beginning index of the iterator is always a boundary position by definition
918     if (offset == 0) {
919         first();       // For side effects on current position, tag values.
920         return TRUE;
921     }
922 
923     if (offset == (int32_t)utext_nativeLength(fText)) {
924         last();       // For side effects on current position, tag values.
925         return TRUE;
926     }
927 
928     // out-of-range indexes are never boundary positions
929     if (offset < 0) {
930         first();       // For side effects on current position, tag values.
931         return FALSE;
932     }
933 
934     if (offset > utext_nativeLength(fText)) {
935         last();        // For side effects on current position, tag values.
936         return FALSE;
937     }
938 
939     // otherwise, we can use following() on the position before the specified
940     // one and return true if the position we get back is the one the user
941     // specified
942     utext_previous32From(fText, offset);
943     int32_t backOne = (int32_t)UTEXT_GETNATIVEINDEX(fText);
944     UBool    result  = following(backOne) == offset;
945     return result;
946 }
947 
948 /**
949  * Returns the current iteration position.
950  * @return The current iteration position.
951  */
current(void) const952 int32_t RuleBasedBreakIterator::current(void) const {
953     int32_t  pos = (int32_t)UTEXT_GETNATIVEINDEX(fText);
954     return pos;
955 }
956 
957 //=======================================================================
958 // implementation
959 //=======================================================================
960 
961 //
962 // RBBIRunMode  -  the state machine runs an extra iteration at the beginning and end
963 //                 of user text.  A variable with this enum type keeps track of where we
964 //                 are.  The state machine only fetches user input while in the RUN mode.
965 //
966 enum RBBIRunMode {
967     RBBI_START,     // state machine processing is before first char of input
968     RBBI_RUN,       // state machine processing is in the user text
969     RBBI_END        // state machine processing is after end of user text.
970 };
971 
972 
973 // Map from look-ahead break states (corresponds to rules) to boundary positions.
974 // Allows multiple lookahead break rules to be in flight at the same time.
975 //
976 // This is a temporary approach for ICU 57. A better fix is to make the look-ahead numbers
977 // in the state table be sequential, then we can just index an array. And the
978 // table could also tell us in advance how big that array needs to be.
979 //
980 // Before ICU 57 there was just a single simple variable for a look-ahead match that
981 // was in progress. Two rules at once did not work.
982 
983 static const int32_t kMaxLookaheads = 8;
984 struct LookAheadResults {
985     int32_t    fUsedSlotLimit;
986     int32_t    fPositions[8];
987     int16_t    fKeys[8];
988 
LookAheadResultsLookAheadResults989     LookAheadResults() : fUsedSlotLimit(0), fPositions(), fKeys() {};
990 
getPositionLookAheadResults991     int32_t getPosition(int16_t key) {
992         for (int32_t i=0; i<fUsedSlotLimit; ++i) {
993             if (fKeys[i] == key) {
994                 return fPositions[i];
995             }
996         }
997         U_ASSERT(FALSE);
998         return -1;
999     }
1000 
setPositionLookAheadResults1001     void setPosition(int16_t key, int32_t position) {
1002         int32_t i;
1003         for (i=0; i<fUsedSlotLimit; ++i) {
1004             if (fKeys[i] == key) {
1005                 fPositions[i] = position;
1006                 return;
1007             }
1008         }
1009         if (i >= kMaxLookaheads) {
1010             U_ASSERT(FALSE);
1011             i = kMaxLookaheads - 1;
1012         }
1013         fKeys[i] = key;
1014         fPositions[i] = position;
1015         U_ASSERT(fUsedSlotLimit == i);
1016         fUsedSlotLimit = i + 1;
1017     }
1018 };
1019 
1020 
1021 //-----------------------------------------------------------------------------------
1022 //
1023 //  handleNext(stateTable)
1024 //     This method is the actual implementation of the rbbi next() method.
1025 //     This method initializes the state machine to state 1
1026 //     and advances through the text character by character until we reach the end
1027 //     of the text or the state machine transitions to state 0.  We update our return
1028 //     value every time the state machine passes through an accepting state.
1029 //
1030 //-----------------------------------------------------------------------------------
handleNext(const RBBIStateTable * statetable)1031 int32_t RuleBasedBreakIterator::handleNext(const RBBIStateTable *statetable) {
1032     int32_t             state;
1033     uint16_t            category        = 0;
1034     RBBIRunMode         mode;
1035 
1036     RBBIStateTableRow  *row;
1037     UChar32             c;
1038     LookAheadResults    lookAheadMatches;
1039     int32_t             result             = 0;
1040     int32_t             initialPosition    = 0;
1041     const char         *tableData          = statetable->fTableData;
1042     uint32_t            tableRowLen        = statetable->fRowLen;
1043 
1044     #ifdef RBBI_DEBUG
1045         if (fTrace) {
1046             RBBIDebugPuts("Handle Next   pos   char  state category");
1047         }
1048     #endif
1049 
1050     // No matter what, handleNext alway correctly sets the break tag value.
1051     fLastStatusIndexValid = TRUE;
1052     fLastRuleStatusIndex = 0;
1053 
1054     // if we're already at the end of the text, return DONE.
1055     initialPosition = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1056     result          = initialPosition;
1057     c               = UTEXT_NEXT32(fText);
1058     if (fData == NULL || c==U_SENTINEL) {
1059         return BreakIterator::DONE;
1060     }
1061 
1062     //  Set the initial state for the state machine
1063     state = START_STATE;
1064     row = (RBBIStateTableRow *)
1065             //(statetable->fTableData + (statetable->fRowLen * state));
1066             (tableData + tableRowLen * state);
1067 
1068 
1069     mode     = RBBI_RUN;
1070     if (statetable->fFlags & RBBI_BOF_REQUIRED) {
1071         category = 2;
1072         mode     = RBBI_START;
1073     }
1074 
1075 
1076     // loop until we reach the end of the text or transition to state 0
1077     //
1078     for (;;) {
1079         if (c == U_SENTINEL) {
1080             // Reached end of input string.
1081             if (mode == RBBI_END) {
1082                 // We have already run the loop one last time with the
1083                 //   character set to the psueudo {eof} value.  Now it is time
1084                 //   to unconditionally bail out.
1085                 break;
1086             }
1087             // Run the loop one last time with the fake end-of-input character category.
1088             mode = RBBI_END;
1089             category = 1;
1090         }
1091 
1092         //
1093         // Get the char category.  An incoming category of 1 or 2 means that
1094         //      we are preset for doing the beginning or end of input, and
1095         //      that we shouldn't get a category from an actual text input character.
1096         //
1097         if (mode == RBBI_RUN) {
1098             // look up the current character's character category, which tells us
1099             // which column in the state table to look at.
1100             // Note:  the 16 in UTRIE_GET16 refers to the size of the data being returned,
1101             //        not the size of the character going in, which is a UChar32.
1102             //
1103             UTRIE_GET16(&fData->fTrie, c, category);
1104 
1105             // Check the dictionary bit in the character's category.
1106             //    Counter is only used by dictionary based iterators (subclasses).
1107             //    Chars that need to be handled by a dictionary have a flag bit set
1108             //    in their category values.
1109             //
1110             if ((category & 0x4000) != 0)  {
1111                 fDictionaryCharCount++;
1112                 //  And off the dictionary flag bit.
1113                 category &= ~0x4000;
1114             }
1115         }
1116 
1117        #ifdef RBBI_DEBUG
1118             if (fTrace) {
1119                 RBBIDebugPrintf("             %4ld   ", utext_getNativeIndex(fText));
1120                 if (0x20<=c && c<0x7f) {
1121                     RBBIDebugPrintf("\"%c\"  ", c);
1122                 } else {
1123                     RBBIDebugPrintf("%5x  ", c);
1124                 }
1125                 RBBIDebugPrintf("%3d  %3d\n", state, category);
1126             }
1127         #endif
1128 
1129         // State Transition - move machine to its next state
1130         //
1131 
1132         // Note: fNextState is defined as uint16_t[2], but we are casting
1133         // a generated RBBI table to RBBIStateTableRow and some tables
1134         // actually have more than 2 categories.
1135         U_ASSERT(category<fData->fHeader->fCatCount);
1136         state = row->fNextState[category];  /*Not accessing beyond memory*/
1137         row = (RBBIStateTableRow *)
1138             // (statetable->fTableData + (statetable->fRowLen * state));
1139             (tableData + tableRowLen * state);
1140 
1141 
1142         if (row->fAccepting == -1) {
1143             // Match found, common case.
1144             if (mode != RBBI_START) {
1145                 result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1146             }
1147             fLastRuleStatusIndex = row->fTagIdx;   // Remember the break status (tag) values.
1148         }
1149 
1150         int16_t completedRule = row->fAccepting;
1151         if (completedRule > 0) {
1152             // Lookahead match is completed.
1153             int32_t lookaheadResult = lookAheadMatches.getPosition(completedRule);
1154             if (lookaheadResult >= 0) {
1155                 fLastRuleStatusIndex = row->fTagIdx;
1156                 UTEXT_SETNATIVEINDEX(fText, lookaheadResult);
1157                 return lookaheadResult;
1158             }
1159         }
1160         int16_t rule = row->fLookAhead;
1161         if (rule != 0) {
1162             // At the position of a '/' in a look-ahead match. Record it.
1163             int32_t  pos = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1164             lookAheadMatches.setPosition(rule, pos);
1165         }
1166 
1167         if (state == STOP_STATE) {
1168             // This is the normal exit from the lookup state machine.
1169             // We have advanced through the string until it is certain that no
1170             //   longer match is possible, no matter what characters follow.
1171             break;
1172         }
1173 
1174         // Advance to the next character.
1175         // If this is a beginning-of-input loop iteration, don't advance
1176         //    the input position.  The next iteration will be processing the
1177         //    first real input character.
1178         if (mode == RBBI_RUN) {
1179             c = UTEXT_NEXT32(fText);
1180         } else {
1181             if (mode == RBBI_START) {
1182                 mode = RBBI_RUN;
1183             }
1184         }
1185 
1186 
1187     }
1188 
1189     // The state machine is done.  Check whether it found a match...
1190 
1191     // If the iterator failed to advance in the match engine, force it ahead by one.
1192     //   (This really indicates a defect in the break rules.  They should always match
1193     //    at least one character.)
1194     if (result == initialPosition) {
1195         UTEXT_SETNATIVEINDEX(fText, initialPosition);
1196         UTEXT_NEXT32(fText);
1197         result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1198     }
1199 
1200     // Leave the iterator at our result position.
1201     UTEXT_SETNATIVEINDEX(fText, result);
1202     #ifdef RBBI_DEBUG
1203         if (fTrace) {
1204             RBBIDebugPrintf("result = %d\n\n", result);
1205         }
1206     #endif
1207     return result;
1208 }
1209 
1210 
1211 
1212 //-----------------------------------------------------------------------------------
1213 //
1214 //  handlePrevious()
1215 //
1216 //      Iterate backwards, according to the logic of the reverse rules.
1217 //      This version handles the exact style backwards rules.
1218 //
1219 //      The logic of this function is very similar to handleNext(), above.
1220 //
1221 //-----------------------------------------------------------------------------------
handlePrevious(const RBBIStateTable * statetable)1222 int32_t RuleBasedBreakIterator::handlePrevious(const RBBIStateTable *statetable) {
1223     int32_t             state;
1224     uint16_t            category        = 0;
1225     RBBIRunMode         mode;
1226     RBBIStateTableRow  *row;
1227     UChar32             c;
1228     LookAheadResults    lookAheadMatches;
1229     int32_t             result          = 0;
1230     int32_t             initialPosition = 0;
1231 
1232     #ifdef RBBI_DEBUG
1233         if (fTrace) {
1234             RBBIDebugPuts("Handle Previous   pos   char  state category");
1235         }
1236     #endif
1237 
1238     // handlePrevious() never gets the rule status.
1239     // Flag the status as invalid; if the user ever asks for status, we will need
1240     // to back up, then re-find the break position using handleNext(), which does
1241     // get the status value.
1242     fLastStatusIndexValid = FALSE;
1243     fLastRuleStatusIndex = 0;
1244 
1245     // if we're already at the start of the text, return DONE.
1246     if (fText == NULL || fData == NULL || UTEXT_GETNATIVEINDEX(fText)==0) {
1247         return BreakIterator::DONE;
1248     }
1249 
1250     //  Set up the starting char.
1251     initialPosition = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1252     result          = initialPosition;
1253     c               = UTEXT_PREVIOUS32(fText);
1254 
1255     //  Set the initial state for the state machine
1256     state = START_STATE;
1257     row = (RBBIStateTableRow *)
1258             (statetable->fTableData + (statetable->fRowLen * state));
1259     category = 3;
1260     mode     = RBBI_RUN;
1261     if (statetable->fFlags & RBBI_BOF_REQUIRED) {
1262         category = 2;
1263         mode     = RBBI_START;
1264     }
1265 
1266 
1267     // loop until we reach the start of the text or transition to state 0
1268     //
1269     for (;;) {
1270         if (c == U_SENTINEL) {
1271             // Reached end of input string.
1272             if (mode == RBBI_END) {
1273                 // We have already run the loop one last time with the
1274                 //   character set to the psueudo {eof} value.  Now it is time
1275                 //   to unconditionally bail out.
1276                 if (result == initialPosition) {
1277                     // Ran off start, no match found.
1278                     // move one index one (towards the start, since we are doing a previous())
1279                     UTEXT_SETNATIVEINDEX(fText, initialPosition);
1280                     (void)UTEXT_PREVIOUS32(fText);   // TODO:  shouldn't be necessary.  We're already at beginning.  Check.
1281                 }
1282                 break;
1283             }
1284             // Run the loop one last time with the fake end-of-input character category.
1285             mode = RBBI_END;
1286             category = 1;
1287         }
1288 
1289         //
1290         // Get the char category.  An incoming category of 1 or 2 means that
1291         //      we are preset for doing the beginning or end of input, and
1292         //      that we shouldn't get a category from an actual text input character.
1293         //
1294         if (mode == RBBI_RUN) {
1295             // look up the current character's character category, which tells us
1296             // which column in the state table to look at.
1297             // Note:  the 16 in UTRIE_GET16 refers to the size of the data being returned,
1298             //        not the size of the character going in, which is a UChar32.
1299             //
1300             UTRIE_GET16(&fData->fTrie, c, category);
1301 
1302             // Check the dictionary bit in the character's category.
1303             //    Counter is only used by dictionary based iterators (subclasses).
1304             //    Chars that need to be handled by a dictionary have a flag bit set
1305             //    in their category values.
1306             //
1307             if ((category & 0x4000) != 0)  {
1308                 fDictionaryCharCount++;
1309                 //  And off the dictionary flag bit.
1310                 category &= ~0x4000;
1311             }
1312         }
1313 
1314         #ifdef RBBI_DEBUG
1315             if (fTrace) {
1316                 RBBIDebugPrintf("             %4d   ", (int32_t)utext_getNativeIndex(fText));
1317                 if (0x20<=c && c<0x7f) {
1318                     RBBIDebugPrintf("\"%c\"  ", c);
1319                 } else {
1320                     RBBIDebugPrintf("%5x  ", c);
1321                 }
1322                 RBBIDebugPrintf("%3d  %3d\n", state, category);
1323             }
1324         #endif
1325 
1326         // State Transition - move machine to its next state
1327         //
1328 
1329         // Note: fNextState is defined as uint16_t[2], but we are casting
1330         // a generated RBBI table to RBBIStateTableRow and some tables
1331         // actually have more than 2 categories.
1332         U_ASSERT(category<fData->fHeader->fCatCount);
1333         state = row->fNextState[category];  /*Not accessing beyond memory*/
1334         row = (RBBIStateTableRow *)
1335             (statetable->fTableData + (statetable->fRowLen * state));
1336 
1337         if (row->fAccepting == -1) {
1338             // Match found, common case.
1339             result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1340         }
1341 
1342         int16_t completedRule = row->fAccepting;
1343         if (completedRule > 0) {
1344             // Lookahead match is completed.
1345             int32_t lookaheadResult = lookAheadMatches.getPosition(completedRule);
1346             if (lookaheadResult >= 0) {
1347                 UTEXT_SETNATIVEINDEX(fText, lookaheadResult);
1348                 return lookaheadResult;
1349             }
1350         }
1351         int16_t rule = row->fLookAhead;
1352         if (rule != 0) {
1353             // At the position of a '/' in a look-ahead match. Record it.
1354             int32_t  pos = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1355             lookAheadMatches.setPosition(rule, pos);
1356         }
1357 
1358         if (state == STOP_STATE) {
1359             // This is the normal exit from the lookup state machine.
1360             // We have advanced through the string until it is certain that no
1361             //   longer match is possible, no matter what characters follow.
1362             break;
1363         }
1364 
1365         // Move (backwards) to the next character to process.
1366         // If this is a beginning-of-input loop iteration, don't advance
1367         //    the input position.  The next iteration will be processing the
1368         //    first real input character.
1369         if (mode == RBBI_RUN) {
1370             c = UTEXT_PREVIOUS32(fText);
1371         } else {
1372             if (mode == RBBI_START) {
1373                 mode = RBBI_RUN;
1374             }
1375         }
1376     }
1377 
1378     // The state machine is done.  Check whether it found a match...
1379 
1380     // If the iterator failed to advance in the match engine, force it ahead by one.
1381     //   (This really indicates a defect in the break rules.  They should always match
1382     //    at least one character.)
1383     if (result == initialPosition) {
1384         UTEXT_SETNATIVEINDEX(fText, initialPosition);
1385         UTEXT_PREVIOUS32(fText);
1386         result = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1387     }
1388 
1389     // Leave the iterator at our result position.
1390     UTEXT_SETNATIVEINDEX(fText, result);
1391     #ifdef RBBI_DEBUG
1392         if (fTrace) {
1393             RBBIDebugPrintf("result = %d\n\n", result);
1394         }
1395     #endif
1396     return result;
1397 }
1398 
1399 
1400 void
reset()1401 RuleBasedBreakIterator::reset()
1402 {
1403     if (fCachedBreakPositions) {
1404         uprv_free(fCachedBreakPositions);
1405     }
1406     fCachedBreakPositions = NULL;
1407     fNumCachedBreakPositions = 0;
1408     fDictionaryCharCount = 0;
1409     fPositionInCache = 0;
1410 }
1411 
1412 
1413 
1414 //-------------------------------------------------------------------------------
1415 //
1416 //   getRuleStatus()   Return the break rule tag associated with the current
1417 //                     iterator position.  If the iterator arrived at its current
1418 //                     position by iterating forwards, the value will have been
1419 //                     cached by the handleNext() function.
1420 //
1421 //                     If no cached status value is available, the status is
1422 //                     found by doing a previous() followed by a next(), which
1423 //                     leaves the iterator where it started, and computes the
1424 //                     status while doing the next().
1425 //
1426 //-------------------------------------------------------------------------------
makeRuleStatusValid()1427 void RuleBasedBreakIterator::makeRuleStatusValid() {
1428     if (fLastStatusIndexValid == FALSE) {
1429         //  No cached status is available.
1430         if (fText == NULL || current() == 0) {
1431             //  At start of text, or there is no text.  Status is always zero.
1432             fLastRuleStatusIndex = 0;
1433             fLastStatusIndexValid = TRUE;
1434         } else {
1435             //  Not at start of text.  Find status the tedious way.
1436             int32_t pa = current();
1437             previous();
1438             if (fNumCachedBreakPositions > 0) {
1439                 reset();                // Blow off the dictionary cache
1440             }
1441             int32_t pb = next();
1442             if (pa != pb) {
1443                 // note: the if (pa != pb) test is here only to eliminate warnings for
1444                 //       unused local variables on gcc.  Logically, it isn't needed.
1445                 U_ASSERT(pa == pb);
1446             }
1447         }
1448     }
1449     U_ASSERT(fLastRuleStatusIndex >= 0  &&  fLastRuleStatusIndex < fData->fStatusMaxIdx);
1450 }
1451 
1452 
getRuleStatus() const1453 int32_t  RuleBasedBreakIterator::getRuleStatus() const {
1454     RuleBasedBreakIterator *nonConstThis  = (RuleBasedBreakIterator *)this;
1455     nonConstThis->makeRuleStatusValid();
1456 
1457     // fLastRuleStatusIndex indexes to the start of the appropriate status record
1458     //                                                 (the number of status values.)
1459     //   This function returns the last (largest) of the array of status values.
1460     int32_t  idx = fLastRuleStatusIndex + fData->fRuleStatusTable[fLastRuleStatusIndex];
1461     int32_t  tagVal = fData->fRuleStatusTable[idx];
1462 
1463     return tagVal;
1464 }
1465 
1466 
1467 
1468 
getRuleStatusVec(int32_t * fillInVec,int32_t capacity,UErrorCode & status)1469 int32_t RuleBasedBreakIterator::getRuleStatusVec(
1470              int32_t *fillInVec, int32_t capacity, UErrorCode &status)
1471 {
1472     if (U_FAILURE(status)) {
1473         return 0;
1474     }
1475 
1476     RuleBasedBreakIterator *nonConstThis  = (RuleBasedBreakIterator *)this;
1477     nonConstThis->makeRuleStatusValid();
1478     int32_t  numVals = fData->fRuleStatusTable[fLastRuleStatusIndex];
1479     int32_t  numValsToCopy = numVals;
1480     if (numVals > capacity) {
1481         status = U_BUFFER_OVERFLOW_ERROR;
1482         numValsToCopy = capacity;
1483     }
1484     int i;
1485     for (i=0; i<numValsToCopy; i++) {
1486         fillInVec[i] = fData->fRuleStatusTable[fLastRuleStatusIndex + i + 1];
1487     }
1488     return numVals;
1489 }
1490 
1491 
1492 
1493 //-------------------------------------------------------------------------------
1494 //
1495 //   getBinaryRules        Access to the compiled form of the rules,
1496 //                         for use by build system tools that save the data
1497 //                         for standard iterator types.
1498 //
1499 //-------------------------------------------------------------------------------
getBinaryRules(uint32_t & length)1500 const uint8_t  *RuleBasedBreakIterator::getBinaryRules(uint32_t &length) {
1501     const uint8_t  *retPtr = NULL;
1502     length = 0;
1503 
1504     if (fData != NULL) {
1505         retPtr = (const uint8_t *)fData->fHeader;
1506         length = fData->fHeader->fLength;
1507     }
1508     return retPtr;
1509 }
1510 
1511 
createBufferClone(void *,int32_t & bufferSize,UErrorCode & status)1512 BreakIterator *  RuleBasedBreakIterator::createBufferClone(void * /*stackBuffer*/,
1513                                    int32_t &bufferSize,
1514                                    UErrorCode &status)
1515 {
1516     if (U_FAILURE(status)){
1517         return NULL;
1518     }
1519 
1520     if (bufferSize == 0) {
1521         bufferSize = 1;  // preflighting for deprecated functionality
1522         return NULL;
1523     }
1524 
1525     BreakIterator *clonedBI = clone();
1526     if (clonedBI == NULL) {
1527         status = U_MEMORY_ALLOCATION_ERROR;
1528     } else {
1529         status = U_SAFECLONE_ALLOCATED_WARNING;
1530     }
1531     return (RuleBasedBreakIterator *)clonedBI;
1532 }
1533 
1534 
1535 //-------------------------------------------------------------------------------
1536 //
1537 //  isDictionaryChar      Return true if the category lookup for this char
1538 //                        indicates that it is in the set of dictionary lookup
1539 //                        chars.
1540 //
1541 //                        This function is intended for use by dictionary based
1542 //                        break iterators.
1543 //
1544 //-------------------------------------------------------------------------------
1545 /*UBool RuleBasedBreakIterator::isDictionaryChar(UChar32   c) {
1546     if (fData == NULL) {
1547         return FALSE;
1548     }
1549     uint16_t category;
1550     UTRIE_GET16(&fData->fTrie, c, category);
1551     return (category & 0x4000) != 0;
1552 }*/
1553 
1554 
1555 //-------------------------------------------------------------------------------
1556 //
1557 //  checkDictionary       This function handles all processing of characters in
1558 //                        the "dictionary" set. It will determine the appropriate
1559 //                        course of action, and possibly set up a cache in the
1560 //                        process.
1561 //
1562 //-------------------------------------------------------------------------------
checkDictionary(int32_t startPos,int32_t endPos,UBool reverse)1563 int32_t RuleBasedBreakIterator::checkDictionary(int32_t startPos,
1564                             int32_t endPos,
1565                             UBool reverse) {
1566     // Reset the old break cache first.
1567     reset();
1568 
1569     // note: code segment below assumes that dictionary chars are in the
1570     // startPos-endPos range
1571     // value returned should be next character in sequence
1572     if ((endPos - startPos) <= 1) {
1573         return (reverse ? startPos : endPos);
1574     }
1575 
1576     // Starting from the starting point, scan towards the proposed result,
1577     // looking for the first dictionary character (which may be the one
1578     // we're on, if we're starting in the middle of a range).
1579     utext_setNativeIndex(fText, reverse ? endPos : startPos);
1580     if (reverse) {
1581         UTEXT_PREVIOUS32(fText);
1582     }
1583 
1584     int32_t rangeStart = startPos;
1585     int32_t rangeEnd = endPos;
1586 
1587     uint16_t    category;
1588     int32_t     current;
1589     UErrorCode  status = U_ZERO_ERROR;
1590     UStack      breaks(status);
1591     int32_t     foundBreakCount = 0;
1592     UChar32     c = utext_current32(fText);
1593 
1594     UTRIE_GET16(&fData->fTrie, c, category);
1595 
1596     // Is the character we're starting on a dictionary character? If so, we
1597     // need to back up to include the entire run; otherwise the results of
1598     // the break algorithm will differ depending on where we start. Since
1599     // the result is cached and there is typically a non-dictionary break
1600     // within a small number of words, there should be little performance impact.
1601     if (category & 0x4000) {
1602         if (reverse) {
1603             do {
1604                 utext_next32(fText);          // TODO:  recast to work directly with postincrement.
1605                 c = utext_current32(fText);
1606                 UTRIE_GET16(&fData->fTrie, c, category);
1607             } while (c != U_SENTINEL && (category & 0x4000));
1608             // Back up to the last dictionary character
1609             rangeEnd = (int32_t)UTEXT_GETNATIVEINDEX(fText);
1610             if (c == U_SENTINEL) {
1611                 // c = fText->last32();
1612                 //   TODO:  why was this if needed?
1613                 c = UTEXT_PREVIOUS32(fText);
1614             }
1615             else {
1616                 c = UTEXT_PREVIOUS32(fText);
1617             }
1618         }
1619         else {
1620             do {
1621                 c = UTEXT_PREVIOUS32(fText);
1622                 UTRIE_GET16(&fData->fTrie, c, category);
1623             }
1624             while (c != U_SENTINEL && (category & 0x4000));
1625             // Back up to the last dictionary character
1626             if (c == U_SENTINEL) {
1627                 // c = fText->first32();
1628                 c = utext_current32(fText);
1629             }
1630             else {
1631                 utext_next32(fText);
1632                 c = utext_current32(fText);
1633             }
1634             rangeStart = (int32_t)UTEXT_GETNATIVEINDEX(fText);;
1635         }
1636         UTRIE_GET16(&fData->fTrie, c, category);
1637     }
1638 
1639     // Loop through the text, looking for ranges of dictionary characters.
1640     // For each span, find the appropriate break engine, and ask it to find
1641     // any breaks within the span.
1642     // Note: we always do this in the forward direction, so that the break
1643     // cache is built in the right order.
1644     if (reverse) {
1645         utext_setNativeIndex(fText, rangeStart);
1646         c = utext_current32(fText);
1647         UTRIE_GET16(&fData->fTrie, c, category);
1648     }
1649     while(U_SUCCESS(status)) {
1650         while((current = (int32_t)UTEXT_GETNATIVEINDEX(fText)) < rangeEnd && (category & 0x4000) == 0) {
1651             utext_next32(fText);           // TODO:  tweak for post-increment operation
1652             c = utext_current32(fText);
1653             UTRIE_GET16(&fData->fTrie, c, category);
1654         }
1655         if (current >= rangeEnd) {
1656             break;
1657         }
1658 
1659         // We now have a dictionary character. Get the appropriate language object
1660         // to deal with it.
1661         const LanguageBreakEngine *lbe = getLanguageBreakEngine(c);
1662 
1663         // Ask the language object if there are any breaks. It will leave the text
1664         // pointer on the other side of its range, ready to search for the next one.
1665         if (lbe != NULL) {
1666             foundBreakCount += lbe->findBreaks(fText, rangeStart, rangeEnd, FALSE, fBreakType, breaks);
1667         }
1668 
1669         // Reload the loop variables for the next go-round
1670         c = utext_current32(fText);
1671         UTRIE_GET16(&fData->fTrie, c, category);
1672     }
1673 
1674     // If we found breaks, build a new break cache. The first and last entries must
1675     // be the original starting and ending position.
1676     if (foundBreakCount > 0) {
1677         U_ASSERT(foundBreakCount == breaks.size());
1678         int32_t totalBreaks = foundBreakCount;
1679         if (startPos < breaks.elementAti(0)) {
1680             totalBreaks += 1;
1681         }
1682         if (endPos > breaks.peeki()) {
1683             totalBreaks += 1;
1684         }
1685         fCachedBreakPositions = (int32_t *)uprv_malloc(totalBreaks * sizeof(int32_t));
1686         if (fCachedBreakPositions != NULL) {
1687             int32_t out = 0;
1688             fNumCachedBreakPositions = totalBreaks;
1689             if (startPos < breaks.elementAti(0)) {
1690                 fCachedBreakPositions[out++] = startPos;
1691             }
1692             for (int32_t i = 0; i < foundBreakCount; ++i) {
1693                 fCachedBreakPositions[out++] = breaks.elementAti(i);
1694             }
1695             if (endPos > fCachedBreakPositions[out-1]) {
1696                 fCachedBreakPositions[out] = endPos;
1697             }
1698             // If there are breaks, then by definition, we are replacing the original
1699             // proposed break by one of the breaks we found. Use following() and
1700             // preceding() to do the work. They should never recurse in this case.
1701             if (reverse) {
1702                 return preceding(endPos);
1703             }
1704             else {
1705                 return following(startPos);
1706             }
1707         }
1708         // If the allocation failed, just fall through to the "no breaks found" case.
1709     }
1710 
1711     // If we get here, there were no language-based breaks. Set the text pointer
1712     // to the original proposed break.
1713     utext_setNativeIndex(fText, reverse ? startPos : endPos);
1714     return (reverse ? startPos : endPos);
1715 }
1716 
1717 U_NAMESPACE_END
1718 
1719 
1720 static icu::UStack *gLanguageBreakFactories = NULL;
1721 static icu::UInitOnce gLanguageBreakFactoriesInitOnce = U_INITONCE_INITIALIZER;
1722 
1723 /**
1724  * Release all static memory held by breakiterator.
1725  */
1726 U_CDECL_BEGIN
breakiterator_cleanup_dict(void)1727 static UBool U_CALLCONV breakiterator_cleanup_dict(void) {
1728     if (gLanguageBreakFactories) {
1729         delete gLanguageBreakFactories;
1730         gLanguageBreakFactories = NULL;
1731     }
1732     gLanguageBreakFactoriesInitOnce.reset();
1733     return TRUE;
1734 }
1735 U_CDECL_END
1736 
1737 U_CDECL_BEGIN
_deleteFactory(void * obj)1738 static void U_CALLCONV _deleteFactory(void *obj) {
1739     delete (icu::LanguageBreakFactory *) obj;
1740 }
1741 U_CDECL_END
1742 U_NAMESPACE_BEGIN
1743 
initLanguageFactories()1744 static void U_CALLCONV initLanguageFactories() {
1745     UErrorCode status = U_ZERO_ERROR;
1746     U_ASSERT(gLanguageBreakFactories == NULL);
1747     gLanguageBreakFactories = new UStack(_deleteFactory, NULL, status);
1748     if (gLanguageBreakFactories != NULL && U_SUCCESS(status)) {
1749         ICULanguageBreakFactory *builtIn = new ICULanguageBreakFactory(status);
1750         gLanguageBreakFactories->push(builtIn, status);
1751 #ifdef U_LOCAL_SERVICE_HOOK
1752         LanguageBreakFactory *extra = (LanguageBreakFactory *)uprv_svc_hook("languageBreakFactory", &status);
1753         if (extra != NULL) {
1754             gLanguageBreakFactories->push(extra, status);
1755         }
1756 #endif
1757     }
1758     ucln_common_registerCleanup(UCLN_COMMON_BREAKITERATOR_DICT, breakiterator_cleanup_dict);
1759 }
1760 
1761 
1762 static const LanguageBreakEngine*
getLanguageBreakEngineFromFactory(UChar32 c,int32_t breakType)1763 getLanguageBreakEngineFromFactory(UChar32 c, int32_t breakType)
1764 {
1765     umtx_initOnce(gLanguageBreakFactoriesInitOnce, &initLanguageFactories);
1766     if (gLanguageBreakFactories == NULL) {
1767         return NULL;
1768     }
1769 
1770     int32_t i = gLanguageBreakFactories->size();
1771     const LanguageBreakEngine *lbe = NULL;
1772     while (--i >= 0) {
1773         LanguageBreakFactory *factory = (LanguageBreakFactory *)(gLanguageBreakFactories->elementAt(i));
1774         lbe = factory->getEngineFor(c, breakType);
1775         if (lbe != NULL) {
1776             break;
1777         }
1778     }
1779     return lbe;
1780 }
1781 
1782 
1783 //-------------------------------------------------------------------------------
1784 //
1785 //  getLanguageBreakEngine  Find an appropriate LanguageBreakEngine for the
1786 //                          the character c.
1787 //
1788 //-------------------------------------------------------------------------------
1789 const LanguageBreakEngine *
getLanguageBreakEngine(UChar32 c)1790 RuleBasedBreakIterator::getLanguageBreakEngine(UChar32 c) {
1791     const LanguageBreakEngine *lbe = NULL;
1792     UErrorCode status = U_ZERO_ERROR;
1793 
1794     if (fLanguageBreakEngines == NULL) {
1795         fLanguageBreakEngines = new UStack(status);
1796         if (fLanguageBreakEngines == NULL || U_FAILURE(status)) {
1797             delete fLanguageBreakEngines;
1798             fLanguageBreakEngines = 0;
1799             return NULL;
1800         }
1801     }
1802 
1803     int32_t i = fLanguageBreakEngines->size();
1804     while (--i >= 0) {
1805         lbe = (const LanguageBreakEngine *)(fLanguageBreakEngines->elementAt(i));
1806         if (lbe->handles(c, fBreakType)) {
1807             return lbe;
1808         }
1809     }
1810 
1811     // No existing dictionary took the character. See if a factory wants to
1812     // give us a new LanguageBreakEngine for this character.
1813     lbe = getLanguageBreakEngineFromFactory(c, fBreakType);
1814 
1815     // If we got one, use it and push it on our stack.
1816     if (lbe != NULL) {
1817         fLanguageBreakEngines->push((void *)lbe, status);
1818         // Even if we can't remember it, we can keep looking it up, so
1819         // return it even if the push fails.
1820         return lbe;
1821     }
1822 
1823     // No engine is forthcoming for this character. Add it to the
1824     // reject set. Create the reject break engine if needed.
1825     if (fUnhandledBreakEngine == NULL) {
1826         fUnhandledBreakEngine = new UnhandledEngine(status);
1827         if (U_SUCCESS(status) && fUnhandledBreakEngine == NULL) {
1828             status = U_MEMORY_ALLOCATION_ERROR;
1829         }
1830         // Put it last so that scripts for which we have an engine get tried
1831         // first.
1832         fLanguageBreakEngines->insertElementAt(fUnhandledBreakEngine, 0, status);
1833         // If we can't insert it, or creation failed, get rid of it
1834         if (U_FAILURE(status)) {
1835             delete fUnhandledBreakEngine;
1836             fUnhandledBreakEngine = 0;
1837             return NULL;
1838         }
1839     }
1840 
1841     // Tell the reject engine about the character; at its discretion, it may
1842     // add more than just the one character.
1843     fUnhandledBreakEngine->handleCharacter(c, fBreakType);
1844 
1845     return fUnhandledBreakEngine;
1846 }
1847 
1848 
1849 
1850 /*int32_t RuleBasedBreakIterator::getBreakType() const {
1851     return fBreakType;
1852 }*/
1853 
setBreakType(int32_t type)1854 void RuleBasedBreakIterator::setBreakType(int32_t type) {
1855     fBreakType = type;
1856     reset();
1857 }
1858 
1859 U_NAMESPACE_END
1860 
1861 #endif /* #if !UCONFIG_NO_BREAK_ITERATION */
1862