/src/icu/source/common/ustr_titlecase_brkiter.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // © 2016 and later: Unicode, Inc. and others. |
2 | | // License & terms of use: http://www.unicode.org/copyright.html |
3 | | /* |
4 | | ******************************************************************************* |
5 | | * Copyright (C) 2011, International Business Machines |
6 | | * Corporation and others. All Rights Reserved. |
7 | | ******************************************************************************* |
8 | | * file name: ustr_titlecase_brkiter.cpp |
9 | | * encoding: UTF-8 |
10 | | * tab size: 8 (not used) |
11 | | * indentation:4 |
12 | | * |
13 | | * created on: 2011may30 |
14 | | * created by: Markus W. Scherer |
15 | | * |
16 | | * Titlecasing functions that are based on BreakIterator |
17 | | * were moved here to break dependency cycles among parts of the common library. |
18 | | */ |
19 | | |
20 | | #include "unicode/utypes.h" |
21 | | |
22 | | #if !UCONFIG_NO_BREAK_ITERATION |
23 | | |
24 | | #include "unicode/brkiter.h" |
25 | | #include "unicode/casemap.h" |
26 | | #include "unicode/chariter.h" |
27 | | #include "unicode/localpointer.h" |
28 | | #include "unicode/ubrk.h" |
29 | | #include "unicode/ucasemap.h" |
30 | | #include "unicode/utext.h" |
31 | | #include "cmemory.h" |
32 | | #include "uassert.h" |
33 | | #include "ucase.h" |
34 | | #include "ucasemap_imp.h" |
35 | | |
36 | | U_NAMESPACE_BEGIN |
37 | | |
38 | | /** |
39 | | * Whole-string BreakIterator. |
40 | | * Titlecasing only calls setText(), first(), and next(). |
41 | | * We implement the rest only to satisfy the abstract interface. |
42 | | */ |
43 | | class WholeStringBreakIterator : public BreakIterator { |
44 | | public: |
45 | 0 | WholeStringBreakIterator() : BreakIterator(), length(0) {} |
46 | | ~WholeStringBreakIterator() U_OVERRIDE; |
47 | | bool operator==(const BreakIterator&) const U_OVERRIDE; |
48 | | WholeStringBreakIterator *clone() const U_OVERRIDE; |
49 | | static UClassID U_EXPORT2 getStaticClassID(); |
50 | | UClassID getDynamicClassID() const U_OVERRIDE; |
51 | | CharacterIterator &getText() const U_OVERRIDE; |
52 | | UText *getUText(UText *fillIn, UErrorCode &errorCode) const U_OVERRIDE; |
53 | | void setText(const UnicodeString &text) U_OVERRIDE; |
54 | | void setText(UText *text, UErrorCode &errorCode) U_OVERRIDE; |
55 | | void adoptText(CharacterIterator* it) U_OVERRIDE; |
56 | | int32_t first() U_OVERRIDE; |
57 | | int32_t last() U_OVERRIDE; |
58 | | int32_t previous() U_OVERRIDE; |
59 | | int32_t next() U_OVERRIDE; |
60 | | int32_t current() const U_OVERRIDE; |
61 | | int32_t following(int32_t offset) U_OVERRIDE; |
62 | | int32_t preceding(int32_t offset) U_OVERRIDE; |
63 | | UBool isBoundary(int32_t offset) U_OVERRIDE; |
64 | | int32_t next(int32_t n) U_OVERRIDE; |
65 | | WholeStringBreakIterator *createBufferClone(void *stackBuffer, int32_t &BufferSize, |
66 | | UErrorCode &errorCode) U_OVERRIDE; |
67 | | WholeStringBreakIterator &refreshInputText(UText *input, UErrorCode &errorCode) U_OVERRIDE; |
68 | | |
69 | | private: |
70 | | int32_t length; |
71 | | }; |
72 | | |
73 | | UOBJECT_DEFINE_RTTI_IMPLEMENTATION(WholeStringBreakIterator) |
74 | | |
75 | 0 | WholeStringBreakIterator::~WholeStringBreakIterator() {} |
76 | 0 | bool WholeStringBreakIterator::operator==(const BreakIterator&) const { return FALSE; } |
77 | 0 | WholeStringBreakIterator *WholeStringBreakIterator::clone() const { return nullptr; } |
78 | | |
79 | 0 | CharacterIterator &WholeStringBreakIterator::getText() const { |
80 | 0 | UPRV_UNREACHABLE; // really should not be called |
81 | 0 | } |
82 | 0 | UText *WholeStringBreakIterator::getUText(UText * /*fillIn*/, UErrorCode &errorCode) const { |
83 | 0 | if (U_SUCCESS(errorCode)) { |
84 | 0 | errorCode = U_UNSUPPORTED_ERROR; |
85 | 0 | } |
86 | 0 | return nullptr; |
87 | 0 | } |
88 | | |
89 | 0 | void WholeStringBreakIterator::setText(const UnicodeString &text) { |
90 | 0 | length = text.length(); |
91 | 0 | } |
92 | 0 | void WholeStringBreakIterator::setText(UText *text, UErrorCode &errorCode) { |
93 | 0 | if (U_SUCCESS(errorCode)) { |
94 | 0 | int64_t length64 = utext_nativeLength(text); |
95 | 0 | if (length64 <= INT32_MAX) { |
96 | 0 | length = (int32_t)length64; |
97 | 0 | } else { |
98 | 0 | errorCode = U_INDEX_OUTOFBOUNDS_ERROR; |
99 | 0 | } |
100 | 0 | } |
101 | 0 | } |
102 | 0 | void WholeStringBreakIterator::adoptText(CharacterIterator*) { |
103 | 0 | UPRV_UNREACHABLE; // should not be called |
104 | 0 | } |
105 | | |
106 | 0 | int32_t WholeStringBreakIterator::first() { return 0; } |
107 | 0 | int32_t WholeStringBreakIterator::last() { return length; } |
108 | 0 | int32_t WholeStringBreakIterator::previous() { return 0; } |
109 | 0 | int32_t WholeStringBreakIterator::next() { return length; } |
110 | 0 | int32_t WholeStringBreakIterator::current() const { return 0; } |
111 | 0 | int32_t WholeStringBreakIterator::following(int32_t /*offset*/) { return length; } |
112 | 0 | int32_t WholeStringBreakIterator::preceding(int32_t /*offset*/) { return 0; } |
113 | 0 | UBool WholeStringBreakIterator::isBoundary(int32_t /*offset*/) { return FALSE; } |
114 | 0 | int32_t WholeStringBreakIterator::next(int32_t /*n*/) { return length; } |
115 | | |
116 | | WholeStringBreakIterator *WholeStringBreakIterator::createBufferClone( |
117 | 0 | void * /*stackBuffer*/, int32_t & /*BufferSize*/, UErrorCode &errorCode) { |
118 | 0 | if (U_SUCCESS(errorCode)) { |
119 | 0 | errorCode = U_UNSUPPORTED_ERROR; |
120 | 0 | } |
121 | 0 | return nullptr; |
122 | 0 | } |
123 | | WholeStringBreakIterator &WholeStringBreakIterator::refreshInputText( |
124 | 0 | UText * /*input*/, UErrorCode &errorCode) { |
125 | 0 | if (U_SUCCESS(errorCode)) { |
126 | 0 | errorCode = U_UNSUPPORTED_ERROR; |
127 | 0 | } |
128 | 0 | return *this; |
129 | 0 | } |
130 | | |
131 | | U_CFUNC |
132 | | BreakIterator *ustrcase_getTitleBreakIterator( |
133 | | const Locale *locale, const char *locID, uint32_t options, BreakIterator *iter, |
134 | 0 | LocalPointer<BreakIterator> &ownedIter, UErrorCode &errorCode) { |
135 | 0 | if (U_FAILURE(errorCode)) { return nullptr; } |
136 | 0 | options &= U_TITLECASE_ITERATOR_MASK; |
137 | 0 | if (options != 0 && iter != nullptr) { |
138 | 0 | errorCode = U_ILLEGAL_ARGUMENT_ERROR; |
139 | 0 | return nullptr; |
140 | 0 | } |
141 | 0 | if (iter == nullptr) { |
142 | 0 | switch (options) { |
143 | 0 | case 0: |
144 | 0 | iter = BreakIterator::createWordInstance( |
145 | 0 | locale != nullptr ? *locale : Locale(locID), errorCode); |
146 | 0 | break; |
147 | 0 | case U_TITLECASE_WHOLE_STRING: |
148 | 0 | iter = new WholeStringBreakIterator(); |
149 | 0 | if (iter == nullptr) { |
150 | 0 | errorCode = U_MEMORY_ALLOCATION_ERROR; |
151 | 0 | } |
152 | 0 | break; |
153 | 0 | case U_TITLECASE_SENTENCES: |
154 | 0 | iter = BreakIterator::createSentenceInstance( |
155 | 0 | locale != nullptr ? *locale : Locale(locID), errorCode); |
156 | 0 | break; |
157 | 0 | default: |
158 | 0 | errorCode = U_ILLEGAL_ARGUMENT_ERROR; |
159 | 0 | break; |
160 | 0 | } |
161 | 0 | ownedIter.adoptInstead(iter); |
162 | 0 | } |
163 | 0 | return iter; |
164 | 0 | } |
165 | | |
166 | | int32_t CaseMap::toTitle( |
167 | | const char *locale, uint32_t options, BreakIterator *iter, |
168 | | const UChar *src, int32_t srcLength, |
169 | | UChar *dest, int32_t destCapacity, Edits *edits, |
170 | 0 | UErrorCode &errorCode) { |
171 | 0 | LocalPointer<BreakIterator> ownedIter; |
172 | 0 | iter = ustrcase_getTitleBreakIterator(nullptr, locale, options, iter, ownedIter, errorCode); |
173 | 0 | if(iter==NULL) { |
174 | 0 | return 0; |
175 | 0 | } |
176 | 0 | UnicodeString s(srcLength<0, src, srcLength); |
177 | 0 | iter->setText(s); |
178 | 0 | return ustrcase_map( |
179 | 0 | ustrcase_getCaseLocale(locale), options, iter, |
180 | 0 | dest, destCapacity, |
181 | 0 | src, srcLength, |
182 | 0 | ustrcase_internalToTitle, edits, errorCode); |
183 | 0 | } |
184 | | |
185 | | U_NAMESPACE_END |
186 | | |
187 | | U_NAMESPACE_USE |
188 | | |
189 | | U_CAPI int32_t U_EXPORT2 |
190 | | u_strToTitle(UChar *dest, int32_t destCapacity, |
191 | | const UChar *src, int32_t srcLength, |
192 | | UBreakIterator *titleIter, |
193 | | const char *locale, |
194 | 0 | UErrorCode *pErrorCode) { |
195 | 0 | LocalPointer<BreakIterator> ownedIter; |
196 | 0 | BreakIterator *iter = ustrcase_getTitleBreakIterator( |
197 | 0 | nullptr, locale, 0, reinterpret_cast<BreakIterator *>(titleIter), |
198 | 0 | ownedIter, *pErrorCode); |
199 | 0 | if (iter == nullptr) { |
200 | 0 | return 0; |
201 | 0 | } |
202 | 0 | UnicodeString s(srcLength<0, src, srcLength); |
203 | 0 | iter->setText(s); |
204 | 0 | return ustrcase_mapWithOverlap( |
205 | 0 | ustrcase_getCaseLocale(locale), 0, iter, |
206 | 0 | dest, destCapacity, |
207 | 0 | src, srcLength, |
208 | 0 | ustrcase_internalToTitle, *pErrorCode); |
209 | 0 | } |
210 | | |
211 | | U_CAPI int32_t U_EXPORT2 |
212 | | ucasemap_toTitle(UCaseMap *csm, |
213 | | UChar *dest, int32_t destCapacity, |
214 | | const UChar *src, int32_t srcLength, |
215 | 0 | UErrorCode *pErrorCode) { |
216 | 0 | if (U_FAILURE(*pErrorCode)) { |
217 | 0 | return 0; |
218 | 0 | } |
219 | 0 | if (csm->iter == NULL) { |
220 | 0 | LocalPointer<BreakIterator> ownedIter; |
221 | 0 | BreakIterator *iter = ustrcase_getTitleBreakIterator( |
222 | 0 | nullptr, csm->locale, csm->options, nullptr, ownedIter, *pErrorCode); |
223 | 0 | if (iter == nullptr) { |
224 | 0 | return 0; |
225 | 0 | } |
226 | 0 | csm->iter = ownedIter.orphan(); |
227 | 0 | } |
228 | 0 | UnicodeString s(srcLength<0, src, srcLength); |
229 | 0 | csm->iter->setText(s); |
230 | 0 | return ustrcase_map( |
231 | 0 | csm->caseLocale, csm->options, csm->iter, |
232 | 0 | dest, destCapacity, |
233 | 0 | src, srcLength, |
234 | 0 | ustrcase_internalToTitle, NULL, *pErrorCode); |
235 | 0 | } |
236 | | |
237 | | #endif // !UCONFIG_NO_BREAK_ITERATION |