1 /*
2 **********************************************************************
3 * Copyright (c) 2014, International Business Machines
4 * Corporation and others.  All Rights Reserved.
5 **********************************************************************
6 */
7 #include "unicode/utypes.h"
8 
9 #if !UCONFIG_NO_FORMATTING
10 
11 #include "unicode/scientificnumberformatter.h"
12 #include "unicode/dcfmtsym.h"
13 #include "unicode/fpositer.h"
14 #include "unicode/utf16.h"
15 #include "unicode/uniset.h"
16 #include "decfmtst.h"
17 #include "unicode/decimfmt.h"
18 
19 U_NAMESPACE_BEGIN
20 
21 static const UChar kSuperscriptDigits[] = {
22         0x2070,
23         0xB9,
24         0xB2,
25         0xB3,
26         0x2074,
27         0x2075,
28         0x2076,
29         0x2077,
30         0x2078,
31         0x2079};
32 
33 static const UChar kSuperscriptPlusSign = 0x207A;
34 static const UChar kSuperscriptMinusSign = 0x207B;
35 
copyAsSuperscript(const UnicodeString & s,int32_t beginIndex,int32_t endIndex,UnicodeString & result,UErrorCode & status)36 static UBool copyAsSuperscript(
37         const UnicodeString &s,
38         int32_t beginIndex,
39         int32_t endIndex,
40         UnicodeString &result,
41         UErrorCode &status) {
42     if (U_FAILURE(status)) {
43         return FALSE;
44     }
45     for (int32_t i = beginIndex; i < endIndex;) {
46         UChar32 c = s.char32At(i);
47         int32_t digit = u_charDigitValue(c);
48         if (digit < 0) {
49             status = U_INVALID_CHAR_FOUND;
50             return FALSE;
51         }
52         result.append(kSuperscriptDigits[digit]);
53         i += U16_LENGTH(c);
54     }
55     return TRUE;
56 }
57 
createSuperscriptInstance(DecimalFormat * fmtToAdopt,UErrorCode & status)58 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance(
59             DecimalFormat *fmtToAdopt, UErrorCode &status) {
60     return createInstance(fmtToAdopt, new SuperscriptStyle(), status);
61 }
62 
createSuperscriptInstance(const Locale & locale,UErrorCode & status)63 ScientificNumberFormatter *ScientificNumberFormatter::createSuperscriptInstance(
64             const Locale &locale, UErrorCode &status) {
65     return createInstance(
66             static_cast<DecimalFormat *>(
67                     DecimalFormat::createScientificInstance(locale, status)),
68             new SuperscriptStyle(),
69             status);
70 }
71 
createMarkupInstance(DecimalFormat * fmtToAdopt,const UnicodeString & beginMarkup,const UnicodeString & endMarkup,UErrorCode & status)72 ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance(
73         DecimalFormat *fmtToAdopt,
74         const UnicodeString &beginMarkup,
75         const UnicodeString &endMarkup,
76         UErrorCode &status) {
77     return createInstance(
78             fmtToAdopt,
79             new MarkupStyle(beginMarkup, endMarkup),
80             status);
81 }
82 
createMarkupInstance(const Locale & locale,const UnicodeString & beginMarkup,const UnicodeString & endMarkup,UErrorCode & status)83 ScientificNumberFormatter *ScientificNumberFormatter::createMarkupInstance(
84         const Locale &locale,
85         const UnicodeString &beginMarkup,
86         const UnicodeString &endMarkup,
87         UErrorCode &status) {
88     return createInstance(
89             static_cast<DecimalFormat *>(
90                     DecimalFormat::createScientificInstance(locale, status)),
91             new MarkupStyle(beginMarkup, endMarkup),
92             status);
93 }
94 
createInstance(DecimalFormat * fmtToAdopt,Style * styleToAdopt,UErrorCode & status)95 ScientificNumberFormatter *ScientificNumberFormatter::createInstance(
96             DecimalFormat *fmtToAdopt,
97             Style *styleToAdopt,
98             UErrorCode &status) {
99     LocalPointer<DecimalFormat> fmt(fmtToAdopt);
100     LocalPointer<Style> style(styleToAdopt);
101     if (U_FAILURE(status)) {
102         return NULL;
103     }
104     ScientificNumberFormatter *result =
105             new ScientificNumberFormatter(
106                     fmt.getAlias(),
107                     style.getAlias(),
108                     status);
109     if (result == NULL) {
110         status = U_MEMORY_ALLOCATION_ERROR;
111         return NULL;
112     }
113     fmt.orphan();
114     style.orphan();
115     if (U_FAILURE(status)) {
116         delete result;
117         return NULL;
118     }
119     return result;
120 }
121 
clone() const122 ScientificNumberFormatter::Style *ScientificNumberFormatter::SuperscriptStyle::clone() const {
123     return new ScientificNumberFormatter::SuperscriptStyle(*this);
124 }
125 
format(const UnicodeString & original,FieldPositionIterator & fpi,const UnicodeString & preExponent,const DecimalFormatStaticSets & staticSets,UnicodeString & appendTo,UErrorCode & status) const126 UnicodeString &ScientificNumberFormatter::SuperscriptStyle::format(
127         const UnicodeString &original,
128         FieldPositionIterator &fpi,
129         const UnicodeString &preExponent,
130         const DecimalFormatStaticSets &staticSets,
131         UnicodeString &appendTo,
132         UErrorCode &status) const {
133     if (U_FAILURE(status)) {
134         return appendTo;
135     }
136     FieldPosition fp;
137     int32_t copyFromOffset = 0;
138     while (fpi.next(fp)) {
139         switch (fp.getField()) {
140         case UNUM_EXPONENT_SYMBOL_FIELD:
141             appendTo.append(
142                     original,
143                     copyFromOffset,
144                     fp.getBeginIndex() - copyFromOffset);
145             copyFromOffset = fp.getEndIndex();
146             appendTo.append(preExponent);
147             break;
148         case UNUM_EXPONENT_SIGN_FIELD:
149             {
150                 int32_t beginIndex = fp.getBeginIndex();
151                 int32_t endIndex = fp.getEndIndex();
152                 UChar32 aChar = original.char32At(beginIndex);
153                 if (staticSets.fMinusSigns->contains(aChar)) {
154                     appendTo.append(
155                             original,
156                             copyFromOffset,
157                             beginIndex - copyFromOffset);
158                     appendTo.append(kSuperscriptMinusSign);
159                 } else if (staticSets.fPlusSigns->contains(aChar)) {
160                     appendTo.append(
161                            original,
162                            copyFromOffset,
163                            beginIndex - copyFromOffset);
164                     appendTo.append(kSuperscriptPlusSign);
165                 } else {
166                     status = U_INVALID_CHAR_FOUND;
167                     return appendTo;
168                 }
169                 copyFromOffset = endIndex;
170             }
171             break;
172         case UNUM_EXPONENT_FIELD:
173             appendTo.append(
174                     original,
175                     copyFromOffset,
176                     fp.getBeginIndex() - copyFromOffset);
177             if (!copyAsSuperscript(
178                     original,
179                     fp.getBeginIndex(),
180                     fp.getEndIndex(),
181                     appendTo,
182                     status)) {
183               return appendTo;
184             }
185             copyFromOffset = fp.getEndIndex();
186             break;
187         default:
188             break;
189         }
190     }
191     appendTo.append(
192             original, copyFromOffset, original.length() - copyFromOffset);
193     return appendTo;
194 }
195 
clone() const196 ScientificNumberFormatter::Style *ScientificNumberFormatter::MarkupStyle::clone() const {
197     return new ScientificNumberFormatter::MarkupStyle(*this);
198 }
199 
format(const UnicodeString & original,FieldPositionIterator & fpi,const UnicodeString & preExponent,const DecimalFormatStaticSets &,UnicodeString & appendTo,UErrorCode & status) const200 UnicodeString &ScientificNumberFormatter::MarkupStyle::format(
201         const UnicodeString &original,
202         FieldPositionIterator &fpi,
203         const UnicodeString &preExponent,
204         const DecimalFormatStaticSets & /*unusedDecimalFormatSets*/,
205         UnicodeString &appendTo,
206         UErrorCode &status) const {
207     if (U_FAILURE(status)) {
208         return appendTo;
209     }
210     FieldPosition fp;
211     int32_t copyFromOffset = 0;
212     while (fpi.next(fp)) {
213         switch (fp.getField()) {
214         case UNUM_EXPONENT_SYMBOL_FIELD:
215             appendTo.append(
216                     original,
217                     copyFromOffset,
218                     fp.getBeginIndex() - copyFromOffset);
219             copyFromOffset = fp.getEndIndex();
220             appendTo.append(preExponent);
221             appendTo.append(fBeginMarkup);
222             break;
223         case UNUM_EXPONENT_FIELD:
224             appendTo.append(
225                     original,
226                     copyFromOffset,
227                     fp.getEndIndex() - copyFromOffset);
228             copyFromOffset = fp.getEndIndex();
229             appendTo.append(fEndMarkup);
230             break;
231         default:
232             break;
233         }
234     }
235     appendTo.append(
236             original, copyFromOffset, original.length() - copyFromOffset);
237     return appendTo;
238 }
239 
ScientificNumberFormatter(DecimalFormat * fmtToAdopt,Style * styleToAdopt,UErrorCode & status)240 ScientificNumberFormatter::ScientificNumberFormatter(
241         DecimalFormat *fmtToAdopt, Style *styleToAdopt, UErrorCode &status)
242         : fPreExponent(),
243           fDecimalFormat(fmtToAdopt),
244           fStyle(styleToAdopt),
245           fStaticSets(NULL) {
246     if (U_FAILURE(status)) {
247         return;
248     }
249     if (fDecimalFormat == NULL || fStyle == NULL) {
250         status = U_ILLEGAL_ARGUMENT_ERROR;
251         return;
252     }
253     const DecimalFormatSymbols *sym = fDecimalFormat->getDecimalFormatSymbols();
254     if (sym == NULL) {
255         status = U_ILLEGAL_ARGUMENT_ERROR;
256         return;
257     }
258     getPreExponent(*sym, fPreExponent);
259     fStaticSets = DecimalFormatStaticSets::getStaticSets(status);
260 }
261 
ScientificNumberFormatter(const ScientificNumberFormatter & other)262 ScientificNumberFormatter::ScientificNumberFormatter(
263         const ScientificNumberFormatter &other)
264         : UObject(other),
265           fPreExponent(other.fPreExponent),
266           fDecimalFormat(NULL),
267           fStyle(NULL),
268           fStaticSets(other.fStaticSets) {
269     fDecimalFormat = static_cast<DecimalFormat *>(
270             other.fDecimalFormat->clone());
271     fStyle = other.fStyle->clone();
272 }
273 
~ScientificNumberFormatter()274 ScientificNumberFormatter::~ScientificNumberFormatter() {
275     delete fDecimalFormat;
276     delete fStyle;
277 }
278 
format(const Formattable & number,UnicodeString & appendTo,UErrorCode & status) const279 UnicodeString &ScientificNumberFormatter::format(
280         const Formattable &number,
281         UnicodeString &appendTo,
282         UErrorCode &status) const {
283     if (U_FAILURE(status)) {
284         return appendTo;
285     }
286     UnicodeString original;
287     FieldPositionIterator fpi;
288     fDecimalFormat->format(number, original, &fpi, status);
289     return fStyle->format(
290             original,
291             fpi,
292             fPreExponent,
293             *fStaticSets,
294             appendTo,
295             status);
296 }
297 
getPreExponent(const DecimalFormatSymbols & dfs,UnicodeString & preExponent)298 void ScientificNumberFormatter::getPreExponent(
299         const DecimalFormatSymbols &dfs, UnicodeString &preExponent) {
300     preExponent.append(dfs.getConstSymbol(
301             DecimalFormatSymbols::kExponentMultiplicationSymbol));
302     preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol));
303     preExponent.append(dfs.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol));
304 }
305 
306 U_NAMESPACE_END
307 
308 #endif /* !UCONFIG_NO_FORMATTING */
309