1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements.  See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License.  You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package java.util;
17
18import java.io.BufferedWriter;
19import java.io.Closeable;
20import java.io.File;
21import java.io.FileNotFoundException;
22import java.io.FileOutputStream;
23import java.io.Flushable;
24import java.io.IOException;
25import java.io.OutputStream;
26import java.io.OutputStreamWriter;
27import java.io.PrintStream;
28import java.io.UnsupportedEncodingException;
29import java.math.BigDecimal;
30import java.math.BigInteger;
31import java.math.MathContext;
32import java.nio.charset.Charset;
33import libcore.icu.LocaleData;
34import libcore.icu.NativeDecimalFormat;
35import libcore.io.IoUtils;
36
37/**
38 * Formats arguments according to a format string (like {@code printf} in C).
39 * <p>
40 * It's relatively rare to use a {@code Formatter} directly. A variety of classes offer convenience
41 * methods for accessing formatter functionality.
42 * Of these, {@link String#format} is generally the most useful.
43 * {@link java.io.PrintStream} and {@link java.io.PrintWriter} both offer
44 * {@code format} and {@code printf} methods.
45 * <p>
46 * <i>Format strings</i> consist of plain text interspersed with format specifiers, such
47 * as {@code "name: %s weight: %03dkg\n"}. Being a Java string, the usual Java string literal
48 * backslash escapes are of course available.
49 * <p>
50 * <i>Format specifiers</i> (such as {@code "%s"} or {@code "%03d"} in the example) start with a
51 * {@code %} and describe how to format their corresponding argument. It includes an optional
52 * argument index, optional flags, an optional width, an optional precision, and a mandatory
53 * conversion type.
54 * In the example, {@code "%s"} has no flags, no width, and no precision, while
55 * {@code "%03d"} has the flag {@code 0}, the width 3, and no precision.
56 * <p>
57 * Not all combinations of argument index, flags, width, precision, and conversion type
58 * are valid.
59 * <p>
60 * <i>Argument index</i>. Normally, each format specifier consumes the next argument to
61 * {@code format}.
62 * For convenient localization, it's possible to reorder arguments so that they appear in a
63 * different order in the output than the order in which they were supplied.
64 * For example, {@code "%4$s"} formats the fourth argument ({@code 4$}) as a string ({@code s}).
65 * It's also possible to reuse an argument with {@code <}. For example,
66 * {@code format("%o %&lt;d %&lt;x", 64)} results in {@code "100 64 40"}.
67 * <p>
68 * <i>Flags</i>. The available flags are:
69 * <p>
70 * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
71 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor"> <TD COLSPAN=4> <B>Flags</B> </TD> </tr>
72 * <tr>
73 * <td width="5%">{@code ,}</td>
74 * <td width="25%">Use grouping separators for large numbers. (Decimal only.)</td>
75 * <td width="30%">{@code format("%,d", 1024);}</td>
76 * <td width="30%">{@code 1,234}</td>
77 * </tr>
78 * <tr>
79 * <td width="5%">{@code +}</td>
80 * <td width="25%">Always show sign. (Decimal only.)</td>
81 * <td width="30%">{@code format("%+d, %+4d", 5, 5);}</td>
82 * <td width="30%"><pre>+5,   +5</pre></td>
83 * </tr>
84 * <tr>
85 * <td width="5%">{@code  }</td>
86 * <td width="25%">A space indicates that non-negative numbers
87 * should have a leading space. (Decimal only.)</td>
88 * <td width="30%">{@code format("x% d% 5d", 4, 4);}</td>
89 * <td width="30%"><pre>x 4    4</pre></td>
90 * </tr>
91 * <tr>
92 * <td width="5%">{@code (}</td>
93 * <td width="25%">Put parentheses around negative numbers. (Decimal only.)</td>
94 * <td width="30%">{@code format("%(d, %(d, %(6d", 12, -12, -12);}</td>
95 * <td width="30%"><pre>12, (12),   (12)</pre></td>
96 * </tr>
97 * <tr>
98 * <td width="5%">{@code -}</td>
99 * <td width="25%">Left-justify. (Requires width.)</td>
100 * <td width="30%">{@code format("%-6dx", 5);}<br/>{@code format("%-3C, %3C", 'd', 0x65);}</td>
101 * <td width="30%"><pre>5      x</pre><br/><pre>D  ,   E</pre></td>
102 * </tr>
103 * <tr>
104 * <td width="5%">{@code 0}</td>
105 * <td width="25%">Pad the number with leading zeros. (Requires width.)</td>
106 * <td width="30%">{@code format("%07d, %03d", 4, 5555);}</td>
107 * <td width="30%">{@code 0000004, 5555}</td>
108 * </tr>
109 * <tr>
110 * <td width="5%">{@code #}</td>
111 * <td width="25%">Alternate form. (Octal and hex only.) </td>
112 * <td width="30%">{@code format("%o %#o", 010, 010);}<br/>{@code format("%x %#x", 0x12, 0x12);}</td>
113 * <td width="30%">{@code 10 010}<br/>{@code 12 0x12}</td>
114 * </tr>
115 * </table>
116 * <p>
117 * <i>Width</i>. The width is a decimal integer specifying the minimum number of characters to be
118 * used to represent the argument. If the result would otherwise be shorter than the width, padding
119 * will be added (the exact details of which depend on the flags). Note that you can't use width to
120 * truncate a field, only to make it wider: see precision for control over the maximum width.
121 * <p>
122 * <i>Precision</i>. The precision is a {@code .} followed by a decimal integer, giving the minimum
123 * number of digits for {@code d}, {@code o}, {@code x}, or {@code X}; the minimum number of digits
124 * after the decimal point for {@code a}, {@code A}, {@code e}, {@code E}, {@code f}, or {@code F};
125 * the maximum number of significant digits for {@code g} or {@code G}; or the maximum number of
126 * characters for {@code s} or {@code S}.
127 * <p>
128 * <i>Conversion type</i>. One or two characters describing how to interpret the argument. Most
129 * conversions are a single character, but date/time conversions all start with {@code t} and
130 * have a single extra character describing the desired output.
131 * <p>
132 * Many conversion types have a corresponding uppercase variant that converts its result to
133 * uppercase using the rules of the relevant locale (either the default or the locale set for
134 * this formatter).
135 * <p>
136 * This table shows the available single-character (non-date/time) conversion types:
137 * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
138 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
139 * <TD COLSPAN=4>
140 * <B>String conversions</B>
141 * <br>
142 * All types are acceptable arguments. Values of type {@link Formattable} have their
143 * {@code formatTo} method invoked; all other types use {@code toString}.
144 * </TD>
145 * </tr>
146 * <tr>
147 * <td width="5%">{@code s}</td>
148 * <td width="25%">String.</td>
149 * <td width="30%">{@code format("%s %s", "hello", "Hello");}</td>
150 * <td width="30%">{@code hello Hello}</td>
151 * </tr>
152 * <tr>
153 * <td width="5%">{@code S}</td>
154 * <td width="25%">Uppercase string.</td>
155 * <td width="30%">{@code format("%S %S", "hello", "Hello");}</td>
156 * <td width="30%">{@code HELLO HELLO}</td>
157 * </tr>
158 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
159 * <TD COLSPAN=4>
160 * <B>Character conversions</B>
161 * <br>
162 * Byte, Character, Short, and Integer (and primitives that box to those types) are all acceptable
163 * as character arguments. Any other type is an error.
164 * </TD>
165 * </tr>
166 * <tr>
167 * <td width="5%">{@code c}</td>
168 * <td width="25%">Character.</td>
169 * <td width="30%">{@code format("%c %c", 'd', 'E');}</td>
170 * <td width="30%">{@code d E}</td>
171 * </tr>
172 * <tr>
173 * <td width="5%">{@code C}</td>
174 * <td width="25%">Uppercase character.</td>
175 * <td width="30%">{@code format("%C %C", 'd', 'E');}</td>
176 * <td width="30%">{@code D E}</td>
177 * </tr>
178 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
179 * <TD COLSPAN=4>
180 * <B>Integer conversions</B>
181 * <br>
182 * Byte, Short, Integer, Long, and BigInteger (and primitives that box to those types) are all
183 * acceptable as integer arguments. Any other type is an error.
184 * </TD>
185 * </tr>
186 * <tr>
187 * <td width="5%">{@code d}</td>
188 * <td width="25%">Decimal.</td>
189 * <td width="30%">{@code format("%d", 26);}</td>
190 * <td width="30%">{@code 26}</td>
191 * </tr>
192 * <tr>
193 * <td width="5%">{@code o}</td>
194 * <td width="25%">Octal.</td>
195 * <td width="30%">{@code format("%o", 032);}</td>
196 * <td width="30%">{@code 32}</td>
197 * </tr>
198 * <tr>
199 * <td width="5%">{@code x}, {@code X}</td>
200 * <td width="25%">Hexadecimal.</td>
201 * <td width="30%">{@code format("%x %X", 0x1a, 0x1a);}</td>
202 * <td width="30%">{@code 1a 1A}</td>
203 * </tr>
204 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
205 * <TD COLSPAN=4><B>Floating-point conversions</B>
206 * <br>
207 * Float, Double, and BigDecimal (and primitives that box to those types) are all acceptable as
208 * floating-point arguments. Any other type is an error.
209 * </TD>
210 * </tr>
211 * <tr>
212 * <td width="5%">{@code f}</td>
213 * <td width="25%">Decimal floating point.</td>
214 * <td width="30%"><pre>
215format("%f", 123.456f);
216format("%.1f", 123.456f);
217format("%1.5f", 123.456f);
218format("%10f", 123.456f);
219format("%6.0f", 123.456f);</td>
220 * <td width="30%" valign="top"><pre>
221123.456001
222123.5
223123.45600
224123.456001
225&nbsp;&nbsp;&nbsp;123</pre></td>
226 * </tr>
227 * <tr>
228 * <td width="5%">{@code e}, {@code E}</td>
229 * <td width="25%">Engineering/exponential floating point.</td>
230 * <td width="30%"><pre>
231format("%e", 123.456f);
232format("%.1e", 123.456f);
233format("%1.5E", 123.456f);
234format("%10E", 123.456f);
235format("%6.0E", 123.456f);</td>
236 * <td width="30%" valign="top"><pre>
2371.234560e+02
2381.2e+02
2391.23456E+02
2401.234560E+02
241&nbsp;1E+02</pre></td>
242 * </tr>
243 * <tr>
244 * <td width="5%" valign="top">{@code g}, {@code G}</td>
245 * <td width="25%" valign="top">Decimal or engineering, depending on the magnitude of the value.</td>
246 * <td width="30%" valign="top">{@code format("%g %g", 0.123, 0.0000123);}</td>
247 * <td width="30%" valign="top">{@code 0.123000 1.23000e-05}</td>
248 * </tr>
249 * <tr>
250 * <td width="5%">{@code a}, {@code A}</td>
251 * <td width="25%">Hexadecimal floating point.</td>
252 * <td width="30%">{@code format("%a", 123.456f);}</td>
253 * <td width="30%">{@code 0x1.edd2f2p6}</td>
254 * </tr>
255 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
256 * <TD COLSPAN=4>
257 * <B>Boolean conversion</B>
258 * <br>
259 * Accepts Boolean values. {@code null} is considered false, and instances of all other
260 * types are considered true.
261 * </TD>
262 * </tr>
263 * <tr>
264 * <td width="5%">{@code b}, {@code B}</td>
265 * <td width="25%">Boolean.</td>
266 * <td width="30%">{@code format("%b %b", true, false);}<br>{@code format("%B %B", true, false);}<br>{@code format("%b", null);}<br>{@code format("%b", "hello");}</td>
267 * <td width="30%">{@code true false}<br>{@code TRUE FALSE}<br>{@code false}<br>{@code true}</td>
268 * </tr>
269 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
270 * <TD COLSPAN=4>
271 * <B>Hash code conversion</B>
272 * <br>
273 * Invokes {@code hashCode} on its argument, which may be of any type.
274 * </TD>
275 * </tr>
276 * <tr>
277 * <td width="5%">{@code h}, {@code H}</td>
278 * <td width="25%">Hexadecimal hash code.</td>
279 * <td width="30%">{@code format("%h", this);}<br>{@code format("%H", this);}<br>{@code format("%h", null);}</td>
280 * <td width="30%">{@code 190d11}<br>{@code 190D11}<br>{@code null}</td>
281 * </tr>
282 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
283 * <TD COLSPAN=4>
284 * <B>Zero-argument conversions</B></TD>
285 * </tr>
286 * <tr>
287 * <td width="5%">{@code %}</td>
288 * <td width="25%">A literal % character.</td>
289 * <td width="30%">{@code format("%d%%", 50);}</td>
290 * <td width="30%">{@code 50%}</td>
291 * </tr>
292 * <tr>
293 * <td width="5%">{@code n}</td>
294 * <td width="25%">Newline. (The value of {@link System#lineSeparator}.)</td>
295 * <td width="30%">{@code format("first%nsecond");}</td>
296 * <td width="30%">{@code first\nsecond}</td>
297 * </tr>
298 * </table>
299 * <p>
300 * It's also possible to format dates and times with {@code Formatter}, though you should
301 * use {@link java.text.SimpleDateFormat} (probably via the factory methods in
302 * {@link java.text.DateFormat}) instead.
303 * The facilities offered by {@code Formatter} are low-level and place the burden of localization
304 * on the developer. Using {@link java.text.DateFormat#getDateInstance},
305 * {@link java.text.DateFormat#getTimeInstance}, and
306 * {@link java.text.DateFormat#getDateTimeInstance} is preferable for dates and times that will be
307 * presented to a human. Those methods will select the best format strings for the user's locale.
308 * <p>
309 * The best non-localized form is <a href="http://en.wikipedia.org/wiki/ISO_8601">ISO 8601</a>,
310 * which you can get with {@code "%tF"} (2010-01-22), {@code "%tF %tR"} (2010-01-22 13:39),
311 * {@code "%tF %tT"} (2010-01-22 13:39:15), or {@code "%tF %tT%z"} (2010-01-22 13:39:15-0800).
312 * <p>
313 * This table shows the date/time conversions, but you should use {@link java.text.SimpleDateFormat}
314 * instead:
315 * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
316 * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
317 * <TD COLSPAN=4><B>Date/time conversions</B>
318 * <br>
319 * Calendar, Date, and Long (representing milliseconds past the epoch) are all acceptable
320 * as date/time arguments. Any other type is an error. The epoch is 1970-01-01 00:00:00 UTC.
321 * <font color="red">Use {@link java.text.SimpleDateFormat} instead.</font>
322 * </TD>
323 * </tr>
324 * <tr>
325 * <td width="5%">{@code ta}</td>
326 * <td width="25%">Localized weekday name (abbreviated).</td>
327 * <td width="30%">{@code format("%ta", cal, cal);}</td>
328 * <td width="30%">{@code Tue}</td>
329 * </tr>
330 * <tr>
331 * <td width="5%">{@code tA}</td>
332 * <td width="25%">Localized weekday name (full).</td>
333 * <td width="30%">{@code format("%tA", cal, cal);}</td>
334 * <td width="30%">{@code Tuesday}</td>
335 * </tr>
336 * <tr>
337 * <td width="5%">{@code tb}</td>
338 * <td width="25%">Localized month name (abbreviated).</td>
339 * <td width="30%">{@code format("%tb", cal);}</td>
340 * <td width="30%">{@code Apr}</td>
341 * </tr>
342 * <tr>
343 * <td width="5%">{@code tB}</td>
344 * <td width="25%">Localized month name (full).</td>
345 * <td width="30%">{@code format("%tB", cal);}</td>
346 * <td width="30%">{@code April}</td>
347 * </tr>
348 * <tr>
349 * <td width="5%">{@code tc}</td>
350 * <td width="25%">C library <i>asctime(3)</i>-like output. Do not use.</td>
351 * <td width="30%">{@code format("%tc", cal);}</td>
352 * <td width="30%">{@code Tue Apr 01 16:19:17 CEST 2008}</td>
353 * </tr>
354 * <tr>
355 * <td width="5%">{@code tC}</td>
356 * <td width="25%">2-digit century.</td>
357 * <td width="30%">{@code format("%tC", cal);}</td>
358 * <td width="30%">{@code 20}</td>
359 * </tr>
360 * <tr>
361 * <td width="5%">{@code td}</td>
362 * <td width="25%">2-digit day of month (01-31).</td>
363 * <td width="30%">{@code format("%td", cal);}</td>
364 * <td width="30%">{@code 01}</td>
365 * </tr>
366 * <tr>
367 * <td width="5%">{@code tD}</td>
368 * <td width="25%">Ambiguous US date format (MM/DD/YY). Do not use.</td>
369 * <td width="30%">{@code format("%tD", cal);}</td>
370 * <td width="30%">{@code 04/01/08}</td>
371 * </tr>
372 * <tr>
373 * <td width="5%">{@code te}</td>
374 * <td width="25%">Day of month (1-31).</td>
375 * <td width="30%">{@code format("%te", cal);}</td>
376 * <td width="30%">{@code 1}</td>
377 * </tr>
378 * <tr>
379 * <td width="5%">{@code tF}</td>
380 * <td width="25%">Full date in ISO 8601 format (YYYY-MM-DD).</td>
381 * <td width="30%">{@code format("%tF", cal);}</td>
382 * <td width="30%">{@code 2008-04-01}</td>
383 * </tr>
384 * <tr>
385 * <td width="5%">{@code th}</td>
386 * <td width="25%">Synonym for {@code %tb}.</td>
387 * <td width="30%"></td>
388 * <td width="30%"></td>
389 * </tr>
390 * <tr>
391 * <td width="5%">{@code tH}</td>
392 * <td width="25%">2-digit 24-hour hour of day (00-23).</td>
393 * <td width="30%">{@code format("%tH", cal);}</td>
394 * <td width="30%">{@code 16}</td>
395 * </tr>
396 * <tr>
397 * <td width="5%">{@code tI}</td>
398 * <td width="25%">2-digit 12-hour hour of day (01-12).</td>
399 * <td width="30%">{@code format("%tI", cal);}</td>
400 * <td width="30%">{@code 04}</td>
401 * </tr>
402 * <tr>
403 * <td width="5%">{@code tj}</td>
404 * <td width="25%">3-digit day of year (001-366).</td>
405 * <td width="30%">{@code format("%tj", cal);}</td>
406 * <td width="30%">{@code 092}</td>
407 * </tr>
408 * <tr>
409 * <td width="5%">{@code tk}</td>
410 * <td width="25%">24-hour hour of day (0-23).</td>
411 * <td width="30%">{@code format("%tk", cal);}</td>
412 * <td width="30%">{@code 16}</td>
413 * </tr>
414 * <tr>
415 * <td width="5%">{@code tl}</td>
416 * <td width="25%">12-hour hour of day (1-12).</td>
417 * <td width="30%">{@code format("%tl", cal);}</td>
418 * <td width="30%">{@code 4}</td>
419 * </tr>
420 * <tr>
421 * <td width="5%">{@code tL}</td>
422 * <td width="25%">Milliseconds.</td>
423 * <td width="30%">{@code format("%tL", cal);}</td>
424 * <td width="30%">{@code 359}</td>
425 * </tr>
426 * <tr>
427 * <td width="5%">{@code tm}</td>
428 * <td width="25%">2-digit month of year (01-12).</td>
429 * <td width="30%">{@code format("%tm", cal);}</td>
430 * <td width="30%">{@code 04}</td>
431 * </tr>
432 * <tr>
433 * <td width="5%">{@code tM}</td>
434 * <td width="25%">2-digit minute.</td>
435 * <td width="30%">{@code format("%tM", cal);}</td>
436 * <td width="30%">{@code 08}</td>
437 * </tr>
438 * <tr>
439 * <td width="5%">{@code tN}</td>
440 * <td width="25%">Nanoseconds.</td>
441 * <td width="30%">{@code format("%tN", cal);}</td>
442 * <td width="30%">{@code 359000000}</td>
443 * </tr>
444 * <tr>
445 * <td width="5%">{@code tp}</td>
446 * <td width="25%">a.m. or p.m.</td>
447 * <td width="30%">{@code format("%tp %Tp", cal, cal);}</td>
448 * <td width="30%">{@code pm PM}</td>
449 * </tr>
450 * <tr>
451 * <td width="5%">{@code tQ}</td>
452 * <td width="25%">Milliseconds since the epoch.</td>
453 * <td width="30%">{@code format("%tQ", cal);}</td>
454 * <td width="30%">{@code 1207059412656}</td>
455 * </tr>
456 * <tr>
457 * <td width="5%">{@code tr}</td>
458 * <td width="25%">Full 12-hour time ({@code %tI:%tM:%tS %Tp}).</td>
459 * <td width="30%">{@code format("%tr", cal);}</td>
460 * <td width="30%">{@code 04:15:32 PM}</td>
461 * </tr>
462 * <tr>
463 * <td width="5%">{@code tR}</td>
464 * <td width="25%">Short 24-hour time ({@code %tH:%tM}).</td>
465 * <td width="30%">{@code format("%tR", cal);}</td>
466 * <td width="30%">{@code 16:15}</td>
467 * </tr>
468 * <tr>
469 * <td width="5%">{@code ts}</td>
470 * <td width="25%">Seconds since the epoch.</td>
471 * <td width="30%">{@code format("%ts", cal);}</td>
472 * <td width="30%">{@code 1207059412}</td>
473 * </tr>
474 * <tr>
475 * <td width="5%">{@code tS}</td>
476 * <td width="25%">2-digit seconds (00-60).</td>
477 * <td width="30%">{@code format("%tS", cal);}</td>
478 * <td width="30%">{@code 17}</td>
479 * </tr>
480 * <tr>
481 * <td width="5%">{@code tT}</td>
482 * <td width="25%">Full 24-hour time ({@code %tH:%tM:%tS}).</td>
483 * <td width="30%">{@code format("%tT", cal);}</td>
484 * <td width="30%">{@code 16:15:32}</td>
485 * </tr>
486 * <tr>
487 * <td width="5%">{@code ty}</td>
488 * <td width="25%">2-digit year (00-99).</td>
489 * <td width="30%">{@code format("%ty", cal);}</td>
490 * <td width="30%">{@code 08}</td>
491 * </tr>
492 * <tr>
493 * <td width="5%">{@code tY}</td>
494 * <td width="25%">4-digit year.</td>
495 * <td width="30%">{@code format("%tY", cal);}</td>
496 * <td width="30%">{@code 2008}</td>
497 * </tr>
498 * <tr>
499 * <td width="5%">{@code tz}</td>
500 * <td width="25%">Time zone GMT offset.</td>
501 * <td width="30%">{@code format("%tz", cal);}</td>
502 * <td width="30%">{@code +0100}</td>
503 * </tr>
504 * <tr>
505 * <td width="5%">{@code tZ}</td>
506 * <td width="25%">Localized time zone abbreviation.</td>
507 * <td width="30%">{@code format("%tZ", cal);}</td>
508 * <td width="30%">{@code CEST}</td>
509 * </tr>
510 * </table>
511 * <p>
512 * As with the other conversions, date/time conversion has an uppercase format. Replacing
513 * {@code %t} with {@code %T} will uppercase the field according to the rules of the formatter's
514 * locale.
515 * <p><i>Number localization</i>. Some conversions use localized decimal digits rather than the
516 * usual ASCII digits. So formatting {@code 123} with {@code %d} will give 123 in English locales
517 * but &#x0661;&#x0662;&#x0663; in appropriate Arabic locales, for example. This number localization
518 * occurs for the decimal integer conversion {@code %d}, the floating point conversions {@code %e},
519 * {@code %f}, and {@code %g}, and all date/time {@code %t} or {@code %T} conversions, but no other
520 * conversions.
521 * <p><i>Thread safety</i>. Formatter is not thread-safe.
522 *
523 * @since 1.5
524 * @see java.text.DateFormat
525 * @see Formattable
526 * @see java.text.SimpleDateFormat
527 */
528public final class Formatter implements Closeable, Flushable {
529    private static final char[] ZEROS = new char[] { '0', '0', '0', '0', '0', '0', '0', '0', '0' };
530
531    /**
532     * The enumeration giving the available styles for formatting very large
533     * decimal numbers.
534     */
535    public enum BigDecimalLayoutForm {
536        /**
537         * Use scientific style for BigDecimals.
538         */
539        SCIENTIFIC,
540        /**
541         * Use normal decimal/float style for BigDecimals.
542         */
543        DECIMAL_FLOAT
544    }
545
546    // User-settable parameters.
547    private Appendable out;
548    private Locale locale;
549
550    // Implementation details.
551    private Object arg;
552    private boolean closed = false;
553    private FormatToken formatToken;
554    private IOException lastIOException;
555    private LocaleData localeData;
556
557    private static class CachedDecimalFormat {
558        public NativeDecimalFormat decimalFormat;
559        public LocaleData currentLocaleData;
560        public String currentPattern;
561
562        public CachedDecimalFormat() {
563        }
564
565        public NativeDecimalFormat update(LocaleData localeData, String pattern) {
566            if (decimalFormat == null) {
567                currentPattern = pattern;
568                currentLocaleData = localeData;
569                decimalFormat = new NativeDecimalFormat(currentPattern, currentLocaleData);
570            }
571            if (!pattern.equals(currentPattern)) {
572                decimalFormat.applyPattern(pattern);
573                currentPattern = pattern;
574            }
575            if (localeData != currentLocaleData) {
576                decimalFormat.setDecimalFormatSymbols(localeData);
577                currentLocaleData = localeData;
578            }
579            return decimalFormat;
580        }
581    }
582
583    private static final ThreadLocal<CachedDecimalFormat> cachedDecimalFormat = new ThreadLocal<CachedDecimalFormat>() {
584        @Override protected CachedDecimalFormat initialValue() {
585            return new CachedDecimalFormat();
586        }
587    };
588
589    /**
590     * Creates a native peer if we don't already have one, or reconfigures an existing one.
591     * This means we get to reuse the peer in cases like "x=%.2f y=%.2f".
592     */
593    private NativeDecimalFormat getDecimalFormat(String pattern) {
594        return cachedDecimalFormat.get().update(localeData, pattern);
595    }
596
597    /**
598     * Constructs a {@code Formatter}.
599     *
600     * <p>The output is written to a {@code StringBuilder} which can be acquired by invoking
601     * {@link #out()} and whose content can be obtained by calling {@code toString}.
602     *
603     * <p>The {@code Locale} used is the user's default locale.
604     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
605     */
606    public Formatter() {
607        this(new StringBuilder(), Locale.getDefault());
608    }
609
610    /**
611     * Constructs a {@code Formatter} whose output will be written to the
612     * specified {@code Appendable}.
613     *
614     * <p>The {@code Locale} used is the user's default locale.
615     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
616     *
617     * @param a
618     *            the output destination of the {@code Formatter}. If {@code a} is {@code null},
619     *            then a {@code StringBuilder} will be used.
620     */
621    public Formatter(Appendable a) {
622        this(a, Locale.getDefault());
623    }
624
625    /**
626     * Constructs a {@code Formatter} with the specified {@code Locale}.
627     *
628     * <p>The output is written to a {@code StringBuilder} which can be acquired by invoking
629     * {@link #out()} and whose content can be obtained by calling {@code toString}.
630     *
631     * @param l
632     *            the {@code Locale} of the {@code Formatter}. If {@code l} is {@code null},
633     *            then no localization will be used.
634     */
635    public Formatter(Locale l) {
636        this(new StringBuilder(), l);
637    }
638
639    /**
640     * Constructs a {@code Formatter} with the specified {@code Locale}
641     * and whose output will be written to the
642     * specified {@code Appendable}.
643     *
644     * @param a
645     *            the output destination of the {@code Formatter}. If {@code a} is {@code null},
646     *            then a {@code StringBuilder} will be used.
647     * @param l
648     *            the {@code Locale} of the {@code Formatter}. If {@code l} is {@code null},
649     *            then no localization will be used.
650     */
651    public Formatter(Appendable a, Locale l) {
652        if (a == null) {
653            out = new StringBuilder();
654        } else {
655            out = a;
656        }
657        locale = l;
658    }
659
660    /**
661     * Constructs a {@code Formatter} whose output is written to the specified file.
662     *
663     * <p>The charset of the {@code Formatter} is the default charset.
664     *
665     * <p>The {@code Locale} used is the user's default locale.
666     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
667     *
668     * @param fileName
669     *            the filename of the file that is used as the output
670     *            destination for the {@code Formatter}. The file will be truncated to
671     *            zero size if the file exists, or else a new file will be
672     *            created. The output of the {@code Formatter} is buffered.
673     * @throws FileNotFoundException
674     *             if the filename does not denote a normal and writable file,
675     *             or if a new file cannot be created, or if any error arises when
676     *             opening or creating the file.
677     */
678    public Formatter(String fileName) throws FileNotFoundException {
679        this(new File(fileName));
680
681    }
682
683    /**
684     * Constructs a {@code Formatter} whose output is written to the specified file.
685     *
686     * <p>The {@code Locale} used is the user's default locale.
687     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
688     *
689     * @param fileName
690     *            the filename of the file that is used as the output
691     *            destination for the {@code Formatter}. The file will be truncated to
692     *            zero size if the file exists, or else a new file will be
693     *            created. The output of the {@code Formatter} is buffered.
694     * @param csn
695     *            the name of the charset for the {@code Formatter}.
696     * @throws FileNotFoundException
697     *             if the filename does not denote a normal and writable file,
698     *             or if a new file cannot be created, or if any error arises when
699     *             opening or creating the file.
700     * @throws UnsupportedEncodingException
701     *             if the charset with the specified name is not supported.
702     */
703    public Formatter(String fileName, String csn) throws FileNotFoundException,
704            UnsupportedEncodingException {
705        this(new File(fileName), csn);
706    }
707
708    /**
709     * Constructs a {@code Formatter} with the given {@code Locale} and charset,
710     * and whose output is written to the specified file.
711     *
712     * @param fileName
713     *            the filename of the file that is used as the output
714     *            destination for the {@code Formatter}. The file will be truncated to
715     *            zero size if the file exists, or else a new file will be
716     *            created. The output of the {@code Formatter} is buffered.
717     * @param csn
718     *            the name of the charset for the {@code Formatter}.
719     * @param l
720     *            the {@code Locale} of the {@code Formatter}. If {@code l} is {@code null},
721     *            then no localization will be used.
722     * @throws FileNotFoundException
723     *             if the filename does not denote a normal and writable file,
724     *             or if a new file cannot be created, or if any error arises when
725     *             opening or creating the file.
726     * @throws UnsupportedEncodingException
727     *             if the charset with the specified name is not supported.
728     */
729    public Formatter(String fileName, String csn, Locale l)
730            throws FileNotFoundException, UnsupportedEncodingException {
731
732        this(new File(fileName), csn, l);
733    }
734
735    /**
736     * Constructs a {@code Formatter} whose output is written to the specified {@code File}.
737     *
738     * The charset of the {@code Formatter} is the default charset.
739     *
740     * <p>The {@code Locale} used is the user's default locale.
741     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
742     *
743     * @param file
744     *            the {@code File} that is used as the output destination for the
745     *            {@code Formatter}. The {@code File} will be truncated to zero size if the {@code File}
746     *            exists, or else a new {@code File} will be created. The output of the
747     *            {@code Formatter} is buffered.
748     * @throws FileNotFoundException
749     *             if the {@code File} is not a normal and writable {@code File}, or if a
750     *             new {@code File} cannot be created, or if any error rises when opening or
751     *             creating the {@code File}.
752     */
753    public Formatter(File file) throws FileNotFoundException {
754        this(new FileOutputStream(file));
755    }
756
757    /**
758     * Constructs a {@code Formatter} with the given charset,
759     * and whose output is written to the specified {@code File}.
760     *
761     * <p>The {@code Locale} used is the user's default locale.
762     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
763     *
764     * @param file
765     *            the {@code File} that is used as the output destination for the
766     *            {@code Formatter}. The {@code File} will be truncated to zero size if the {@code File}
767     *            exists, or else a new {@code File} will be created. The output of the
768     *            {@code Formatter} is buffered.
769     * @param csn
770     *            the name of the charset for the {@code Formatter}.
771     * @throws FileNotFoundException
772     *             if the {@code File} is not a normal and writable {@code File}, or if a
773     *             new {@code File} cannot be created, or if any error rises when opening or
774     *             creating the {@code File}.
775     * @throws UnsupportedEncodingException
776     *             if the charset with the specified name is not supported.
777     */
778    public Formatter(File file, String csn) throws FileNotFoundException,
779            UnsupportedEncodingException {
780        this(file, csn, Locale.getDefault());
781    }
782
783    /**
784     * Constructs a {@code Formatter} with the given {@code Locale} and charset,
785     * and whose output is written to the specified {@code File}.
786     *
787     * @param file
788     *            the {@code File} that is used as the output destination for the
789     *            {@code Formatter}. The {@code File} will be truncated to zero size if the {@code File}
790     *            exists, or else a new {@code File} will be created. The output of the
791     *            {@code Formatter} is buffered.
792     * @param csn
793     *            the name of the charset for the {@code Formatter}.
794     * @param l
795     *            the {@code Locale} of the {@code Formatter}. If {@code l} is {@code null},
796     *            then no localization will be used.
797     * @throws FileNotFoundException
798     *             if the {@code File} is not a normal and writable {@code File}, or if a
799     *             new {@code File} cannot be created, or if any error rises when opening or
800     *             creating the {@code File}.
801     * @throws UnsupportedEncodingException
802     *             if the charset with the specified name is not supported.
803     */
804    public Formatter(File file, String csn, Locale l)
805            throws FileNotFoundException, UnsupportedEncodingException {
806        FileOutputStream fout = null;
807        try {
808            fout = new FileOutputStream(file);
809            out = new BufferedWriter(new OutputStreamWriter(fout, csn));
810        } catch (RuntimeException e) {
811            IoUtils.closeQuietly(fout);
812            throw e;
813        } catch (UnsupportedEncodingException e) {
814            IoUtils.closeQuietly(fout);
815            throw e;
816        }
817
818        locale = l;
819    }
820
821    /**
822     * Constructs a {@code Formatter} whose output is written to the specified {@code OutputStream}.
823     *
824     * <p>The charset of the {@code Formatter} is the default charset.
825     *
826     * <p>The {@code Locale} used is the user's default locale.
827     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
828     *
829     * @param os
830     *            the stream to be used as the destination of the {@code Formatter}.
831     */
832    public Formatter(OutputStream os) {
833        out = new BufferedWriter(new OutputStreamWriter(os, Charset.defaultCharset()));
834        locale = Locale.getDefault();
835    }
836
837    /**
838     * Constructs a {@code Formatter} with the given charset,
839     * and whose output is written to the specified {@code OutputStream}.
840     *
841     * <p>The {@code Locale} used is the user's default locale.
842     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
843     *
844     * @param os
845     *            the stream to be used as the destination of the {@code Formatter}.
846     * @param csn
847     *            the name of the charset for the {@code Formatter}.
848     * @throws UnsupportedEncodingException
849     *             if the charset with the specified name is not supported.
850     */
851    public Formatter(OutputStream os, String csn) throws UnsupportedEncodingException {
852        this(os, csn, Locale.getDefault());
853    }
854
855    /**
856     * Constructs a {@code Formatter} with the given {@code Locale} and charset,
857     * and whose output is written to the specified {@code OutputStream}.
858     *
859     * @param os
860     *            the stream to be used as the destination of the {@code Formatter}.
861     * @param csn
862     *            the name of the charset for the {@code Formatter}.
863     * @param l
864     *            the {@code Locale} of the {@code Formatter}. If {@code l} is {@code null},
865     *            then no localization will be used.
866     * @throws UnsupportedEncodingException
867     *             if the charset with the specified name is not supported.
868     */
869    public Formatter(OutputStream os, String csn, Locale l) throws UnsupportedEncodingException {
870        out = new BufferedWriter(new OutputStreamWriter(os, csn));
871        locale = l;
872    }
873
874    /**
875     * Constructs a {@code Formatter} whose output is written to the specified {@code PrintStream}.
876     *
877     * <p>The charset of the {@code Formatter} is the default charset.
878     *
879     * <p>The {@code Locale} used is the user's default locale.
880     * See "<a href="../util/Locale.html#default_locale">Be wary of the default locale</a>".
881     *
882     * @param ps
883     *            the {@code PrintStream} used as destination of the {@code Formatter}. If
884     *            {@code ps} is {@code null}, then a {@code NullPointerException} will
885     *            be raised.
886     */
887    public Formatter(PrintStream ps) {
888        if (ps == null) {
889            throw new NullPointerException("ps == null");
890        }
891        out = ps;
892        locale = Locale.getDefault();
893    }
894
895    private void checkNotClosed() {
896        if (closed) {
897            throw new FormatterClosedException();
898        }
899    }
900
901    /**
902     * Returns the {@code Locale} of the {@code Formatter}.
903     *
904     * @return the {@code Locale} for the {@code Formatter} or {@code null} for no {@code Locale}.
905     * @throws FormatterClosedException
906     *             if the {@code Formatter} has been closed.
907     */
908    public Locale locale() {
909        checkNotClosed();
910        return locale;
911    }
912
913    /**
914     * Returns the output destination of the {@code Formatter}.
915     *
916     * @return the output destination of the {@code Formatter}.
917     * @throws FormatterClosedException
918     *             if the {@code Formatter} has been closed.
919     */
920    public Appendable out() {
921        checkNotClosed();
922        return out;
923    }
924
925    /**
926     * Returns the content by calling the {@code toString()} method of the output
927     * destination.
928     *
929     * @return the content by calling the {@code toString()} method of the output
930     *         destination.
931     * @throws FormatterClosedException
932     *             if the {@code Formatter} has been closed.
933     */
934    @Override
935    public String toString() {
936        checkNotClosed();
937        return out.toString();
938    }
939
940    /**
941     * Flushes the {@code Formatter}. If the output destination is {@link Flushable},
942     * then the method {@code flush()} will be called on that destination.
943     *
944     * @throws FormatterClosedException
945     *             if the {@code Formatter} has been closed.
946     */
947    public void flush() {
948        checkNotClosed();
949        if (out instanceof Flushable) {
950            try {
951                ((Flushable) out).flush();
952            } catch (IOException e) {
953                lastIOException = e;
954            }
955        }
956    }
957
958    /**
959     * Closes the {@code Formatter}. If the output destination is {@link Closeable},
960     * then the method {@code close()} will be called on that destination.
961     *
962     * If the {@code Formatter} has been closed, then calling the this method will have no
963     * effect.
964     *
965     * Any method but the {@link #ioException()} that is called after the
966     * {@code Formatter} has been closed will raise a {@code FormatterClosedException}.
967     */
968    public void close() {
969        if (!closed) {
970            closed = true;
971            try {
972                if (out instanceof Closeable) {
973                    ((Closeable) out).close();
974                }
975            } catch (IOException e) {
976                lastIOException = e;
977            }
978        }
979    }
980
981    /**
982     * Returns the last {@code IOException} thrown by the {@code Formatter}'s output
983     * destination. If the {@code append()} method of the destination does not throw
984     * {@code IOException}s, the {@code ioException()} method will always return {@code null}.
985     *
986     * @return the last {@code IOException} thrown by the {@code Formatter}'s output
987     *         destination.
988     */
989    public IOException ioException() {
990        return lastIOException;
991    }
992
993    /**
994     * Writes a formatted string to the output destination of the {@code Formatter}.
995     *
996     * @param format
997     *            a format string.
998     * @param args
999     *            the arguments list used in the {@code format()} method. If there are
1000     *            more arguments than those specified by the format string, then
1001     *            the additional arguments are ignored.
1002     * @return this {@code Formatter}.
1003     * @throws IllegalFormatException
1004     *             if the format string is illegal or incompatible with the
1005     *             arguments, or if fewer arguments are sent than those required by
1006     *             the format string, or any other illegal situation.
1007     * @throws FormatterClosedException
1008     *             if the {@code Formatter} has been closed.
1009     */
1010    public Formatter format(String format, Object... args) {
1011        return format(this.locale, format, args);
1012    }
1013
1014    /**
1015     * Writes a formatted string to the output destination of the {@code Formatter}.
1016     *
1017     * @param l
1018     *            the {@code Locale} used in the method. If {@code locale} is
1019     *            {@code null}, then no localization will be applied. This
1020     *            parameter does not change this Formatter's default {@code Locale}
1021     *            as specified during construction, and only applies for the
1022     *            duration of this call.
1023     * @param format
1024     *            a format string.
1025     * @param args
1026     *            the arguments list used in the {@code format()} method. If there are
1027     *            more arguments than those specified by the format string, then
1028     *            the additional arguments are ignored.
1029     * @return this {@code Formatter}.
1030     * @throws IllegalFormatException
1031     *             if the format string is illegal or incompatible with the
1032     *             arguments, or if fewer arguments are sent than those required by
1033     *             the format string, or any other illegal situation.
1034     * @throws FormatterClosedException
1035     *             if the {@code Formatter} has been closed.
1036     */
1037    public Formatter format(Locale l, String format, Object... args) {
1038        Locale originalLocale = locale;
1039        try {
1040            this.locale = (l == null ? Locale.US : l);
1041            this.localeData = LocaleData.get(locale);
1042            doFormat(format, args);
1043        } finally {
1044            this.locale = originalLocale;
1045        }
1046        return this;
1047    }
1048
1049    private void doFormat(String format, Object... args) {
1050        checkNotClosed();
1051
1052        FormatSpecifierParser fsp = new FormatSpecifierParser(format);
1053        int currentObjectIndex = 0;
1054        Object lastArgument = null;
1055        boolean hasLastArgumentSet = false;
1056
1057        int length = format.length();
1058        int i = 0;
1059        while (i < length) {
1060            // Find the maximal plain-text sequence...
1061            int plainTextStart = i;
1062            int nextPercent = format.indexOf('%', i);
1063            int plainTextEnd = (nextPercent == -1) ? length : nextPercent;
1064            // ...and output it.
1065            if (plainTextEnd > plainTextStart) {
1066                outputCharSequence(format, plainTextStart, plainTextEnd);
1067            }
1068            i = plainTextEnd;
1069            // Do we have a format specifier?
1070            if (i < length) {
1071                FormatToken token = fsp.parseFormatToken(i + 1);
1072
1073                Object argument = null;
1074                if (token.requireArgument()) {
1075                    int index = token.getArgIndex() == FormatToken.UNSET ? currentObjectIndex++ : token.getArgIndex();
1076                    argument = getArgument(args, index, fsp, lastArgument, hasLastArgumentSet);
1077                    lastArgument = argument;
1078                    hasLastArgumentSet = true;
1079                }
1080
1081                CharSequence substitution = transform(token, argument);
1082                // The substitution is null if we called Formattable.formatTo.
1083                if (substitution != null) {
1084                    outputCharSequence(substitution, 0, substitution.length());
1085                }
1086                i = fsp.i;
1087            }
1088        }
1089    }
1090
1091    // Fixes http://code.google.com/p/android/issues/detail?id=1767.
1092    private void outputCharSequence(CharSequence cs, int start, int end) {
1093        try {
1094            out.append(cs, start, end);
1095        } catch (IOException e) {
1096            lastIOException = e;
1097        }
1098    }
1099
1100    private Object getArgument(Object[] args, int index, FormatSpecifierParser fsp,
1101            Object lastArgument, boolean hasLastArgumentSet) {
1102        if (index == FormatToken.LAST_ARGUMENT_INDEX && !hasLastArgumentSet) {
1103            throw new MissingFormatArgumentException("<");
1104        }
1105
1106        if (args == null) {
1107            return null;
1108        }
1109
1110        if (index >= args.length) {
1111            throw new MissingFormatArgumentException(fsp.getFormatSpecifierText());
1112        }
1113
1114        if (index == FormatToken.LAST_ARGUMENT_INDEX) {
1115            return lastArgument;
1116        }
1117
1118        return args[index];
1119    }
1120
1121    /*
1122     * Complete details of a single format specifier parsed from a format string.
1123     */
1124    private static class FormatToken {
1125        static final int LAST_ARGUMENT_INDEX = -2;
1126
1127        static final int UNSET = -1;
1128
1129        static final int FLAGS_UNSET = 0;
1130
1131        static final int DEFAULT_PRECISION = 6;
1132
1133        static final int FLAG_ZERO = 1 << 4;
1134
1135        private int argIndex = UNSET;
1136
1137        // These have package access for performance. They used to be represented by an int bitmask
1138        // and accessed via methods, but Android's JIT doesn't yet do a good job of such code.
1139        // Direct field access, on the other hand, is fast.
1140        boolean flagComma;
1141        boolean flagMinus;
1142        boolean flagParenthesis;
1143        boolean flagPlus;
1144        boolean flagSharp;
1145        boolean flagSpace;
1146        boolean flagZero;
1147
1148        private char conversionType = (char) UNSET;
1149        private char dateSuffix;
1150
1151        private int precision = UNSET;
1152        private int width = UNSET;
1153
1154        private StringBuilder strFlags;
1155
1156        // Tests whether there were no flags, no width, and no precision specified.
1157        boolean isDefault() {
1158            return !flagComma && !flagMinus && !flagParenthesis && !flagPlus && !flagSharp &&
1159                    !flagSpace && !flagZero && width == UNSET && precision == UNSET;
1160        }
1161
1162        boolean isPrecisionSet() {
1163            return precision != UNSET;
1164        }
1165
1166        int getArgIndex() {
1167            return argIndex;
1168        }
1169
1170        void setArgIndex(int index) {
1171            argIndex = index;
1172        }
1173
1174        int getWidth() {
1175            return width;
1176        }
1177
1178        void setWidth(int width) {
1179            this.width = width;
1180        }
1181
1182        int getPrecision() {
1183            return precision;
1184        }
1185
1186        void setPrecision(int precise) {
1187            this.precision = precise;
1188        }
1189
1190        String getStrFlags() {
1191            return (strFlags != null) ? strFlags.toString() : "";
1192        }
1193
1194        /*
1195         * Sets qualified char as one of the flags. If the char is qualified,
1196         * sets it as a flag and returns true. Or else returns false.
1197         */
1198        boolean setFlag(int ch) {
1199            boolean dupe = false;
1200            switch (ch) {
1201            case ',':
1202                dupe = flagComma;
1203                flagComma = true;
1204                break;
1205            case '-':
1206                dupe = flagMinus;
1207                flagMinus = true;
1208                break;
1209            case '(':
1210                dupe = flagParenthesis;
1211                flagParenthesis = true;
1212                break;
1213            case '+':
1214                dupe = flagPlus;
1215                flagPlus = true;
1216                break;
1217            case '#':
1218                dupe = flagSharp;
1219                flagSharp = true;
1220                break;
1221            case ' ':
1222                dupe = flagSpace;
1223                flagSpace = true;
1224                break;
1225            case '0':
1226                dupe = flagZero;
1227                flagZero = true;
1228                break;
1229            default:
1230                return false;
1231            }
1232            if (dupe) {
1233                // The RI documentation implies we're supposed to report all the flags, not just
1234                // the first duplicate, but the RI behaves the same as we do.
1235                throw new DuplicateFormatFlagsException(String.valueOf(ch));
1236            }
1237            if (strFlags == null) {
1238                strFlags = new StringBuilder(7); // There are seven possible flags.
1239            }
1240            strFlags.append((char) ch);
1241            return true;
1242        }
1243
1244        char getConversionType() {
1245            return conversionType;
1246        }
1247
1248        void setConversionType(char c) {
1249            conversionType = c;
1250        }
1251
1252        char getDateSuffix() {
1253            return dateSuffix;
1254        }
1255
1256        void setDateSuffix(char c) {
1257            dateSuffix = c;
1258        }
1259
1260        boolean requireArgument() {
1261            return conversionType != '%' && conversionType != 'n';
1262        }
1263
1264        void checkFlags(Object arg) {
1265            // Work out which flags are allowed.
1266            boolean allowComma = false;
1267            boolean allowMinus = true;
1268            boolean allowParenthesis = false;
1269            boolean allowPlus = false;
1270            boolean allowSharp = false;
1271            boolean allowSpace = false;
1272            boolean allowZero = false;
1273            // Precision and width?
1274            boolean allowPrecision = true;
1275            boolean allowWidth = true;
1276            // Argument?
1277            boolean allowArgument = true;
1278            switch (conversionType) {
1279            // Character and date/time.
1280            case 'c': case 'C': case 't': case 'T':
1281                // Only '-' is allowed.
1282                allowPrecision = false;
1283                break;
1284
1285            // String.
1286            case 's': case 'S':
1287                if (arg instanceof Formattable) {
1288                    allowSharp = true;
1289                }
1290                break;
1291
1292            // Floating point.
1293            case 'g': case 'G':
1294                allowComma = allowParenthesis = allowPlus = allowSpace = allowZero = true;
1295                break;
1296            case 'f':
1297                allowComma = allowParenthesis = allowPlus = allowSharp = allowSpace = allowZero = true;
1298                break;
1299            case 'e': case 'E':
1300                allowParenthesis = allowPlus = allowSharp = allowSpace = allowZero = true;
1301                break;
1302            case 'a': case 'A':
1303                allowPlus = allowSharp = allowSpace = allowZero = true;
1304                break;
1305
1306            // Integral.
1307            case 'd':
1308                allowComma = allowParenthesis = allowPlus = allowSpace = allowZero = true;
1309                allowPrecision = false;
1310                break;
1311            case 'o': case 'x': case 'X':
1312                allowSharp = allowZero = true;
1313                if (arg == null || arg instanceof BigInteger) {
1314                    allowParenthesis = allowPlus = allowSpace = true;
1315                }
1316                allowPrecision = false;
1317                break;
1318
1319            // Special.
1320            case 'n':
1321                // Nothing is allowed.
1322                allowMinus = false;
1323                allowArgument = allowPrecision = allowWidth = false;
1324                break;
1325            case '%':
1326                // The only flag allowed is '-', and no argument or precision is allowed.
1327                allowArgument = false;
1328                allowPrecision = false;
1329                break;
1330
1331            // Booleans and hash codes.
1332            case 'b': case 'B': case 'h': case 'H':
1333                break;
1334
1335            default:
1336                throw unknownFormatConversionException();
1337            }
1338
1339            // Check for disallowed flags.
1340            String mismatch = null;
1341            if (!allowComma && flagComma) {
1342                mismatch = ",";
1343            } else if (!allowMinus && flagMinus) {
1344                mismatch = "-";
1345            } else if (!allowParenthesis && flagParenthesis) {
1346                mismatch = "(";
1347            } else if (!allowPlus && flagPlus) {
1348                mismatch = "+";
1349            } else if (!allowSharp && flagSharp) {
1350                mismatch = "#";
1351            } else if (!allowSpace && flagSpace) {
1352                mismatch = " ";
1353            } else if (!allowZero && flagZero) {
1354                mismatch = "0";
1355            }
1356            if (mismatch != null) {
1357                if (conversionType == 'n') {
1358                    // For no good reason, %n is a special case...
1359                    throw new IllegalFormatFlagsException(mismatch);
1360                } else {
1361                    throw new FormatFlagsConversionMismatchException(mismatch, conversionType);
1362                }
1363            }
1364
1365            // Check for a missing width with flags that require a width.
1366            if ((flagMinus || flagZero) && width == UNSET) {
1367                throw new MissingFormatWidthException("-" + conversionType);
1368            }
1369
1370            // Check that no-argument conversion types don't have an argument.
1371            // Note: the RI doesn't enforce this.
1372            if (!allowArgument && argIndex != UNSET) {
1373                throw new IllegalFormatFlagsException("%" + conversionType +
1374                        " doesn't take an argument");
1375            }
1376
1377            // Check that we don't have a precision or width where they're not allowed.
1378            if (!allowPrecision && precision != UNSET) {
1379                throw new IllegalFormatPrecisionException(precision);
1380            }
1381            if (!allowWidth && width != UNSET) {
1382                throw new IllegalFormatWidthException(width);
1383            }
1384
1385            // Some combinations make no sense...
1386            if (flagPlus && flagSpace) {
1387                throw new IllegalFormatFlagsException("the '+' and ' ' flags are incompatible");
1388            }
1389            if (flagMinus && flagZero) {
1390                throw new IllegalFormatFlagsException("the '-' and '0' flags are incompatible");
1391            }
1392        }
1393
1394        public UnknownFormatConversionException unknownFormatConversionException() {
1395            if (conversionType == 't' || conversionType == 'T') {
1396                throw new UnknownFormatConversionException(String.format("%c%c",
1397                        conversionType, dateSuffix));
1398            }
1399            throw new UnknownFormatConversionException(String.valueOf(conversionType));
1400        }
1401    }
1402
1403    /*
1404     * Gets the formatted string according to the format token and the
1405     * argument.
1406     */
1407    private CharSequence transform(FormatToken token, Object argument) {
1408        this.formatToken = token;
1409        this.arg = argument;
1410
1411        // There are only two format specifiers that matter: "%d" and "%s".
1412        // Nothing else is common in the wild. We fast-path these two to
1413        // avoid the heavyweight machinery needed to cope with flags, width,
1414        // and precision.
1415        if (token.isDefault()) {
1416            switch (token.getConversionType()) {
1417            case 's':
1418                if (arg == null) {
1419                    return "null";
1420                } else if (!(arg instanceof Formattable)) {
1421                    return arg.toString();
1422                }
1423                break;
1424            case 'd':
1425                boolean needLocalizedDigits = (localeData.zeroDigit != '0');
1426                if (out instanceof StringBuilder && !needLocalizedDigits) {
1427                    if (arg instanceof Integer || arg instanceof Short || arg instanceof Byte) {
1428                        IntegralToString.appendInt((StringBuilder) out, ((Number) arg).intValue());
1429                        return null;
1430                    } else if (arg instanceof Long) {
1431                        IntegralToString.appendLong((StringBuilder) out, ((Long) arg).longValue());
1432                        return null;
1433                    }
1434                }
1435                if (arg instanceof Integer || arg instanceof Long || arg instanceof Short || arg instanceof Byte) {
1436                    String result = arg.toString();
1437                    return needLocalizedDigits ? localizeDigits(result) : result;
1438                }
1439            }
1440        }
1441
1442        formatToken.checkFlags(arg);
1443        CharSequence result;
1444        switch (token.getConversionType()) {
1445        case 'B': case 'b':
1446            result = transformFromBoolean();
1447            break;
1448        case 'H': case 'h':
1449            result = transformFromHashCode();
1450            break;
1451        case 'S': case 's':
1452            result = transformFromString();
1453            break;
1454        case 'C': case 'c':
1455            result = transformFromCharacter();
1456            break;
1457        case 'd': case 'o': case 'x': case 'X':
1458            if (arg == null || arg instanceof BigInteger) {
1459                result = transformFromBigInteger();
1460            } else {
1461                result = transformFromInteger();
1462            }
1463            break;
1464        case 'A': case 'a': case 'E': case 'e': case 'f': case 'G': case 'g':
1465            result = transformFromFloat();
1466            break;
1467        case '%':
1468            result = transformFromPercent();
1469            break;
1470        case 'n':
1471            result = System.lineSeparator();
1472            break;
1473        case 't': case 'T':
1474            result = transformFromDateTime();
1475            break;
1476        default:
1477            throw token.unknownFormatConversionException();
1478        }
1479
1480        if (Character.isUpperCase(token.getConversionType())) {
1481            if (result != null) {
1482                result = result.toString().toUpperCase(locale);
1483            }
1484        }
1485        return result;
1486    }
1487
1488    private IllegalFormatConversionException badArgumentType() {
1489        throw new IllegalFormatConversionException(formatToken.getConversionType(), arg.getClass());
1490    }
1491
1492    /**
1493     * Returns a CharSequence corresponding to {@code s} with all the ASCII digits replaced
1494     * by digits appropriate to this formatter's locale. Other characters remain unchanged.
1495     */
1496    private CharSequence localizeDigits(CharSequence s) {
1497        int length = s.length();
1498        int offsetToLocalizedDigits = localeData.zeroDigit - '0';
1499        StringBuilder result = new StringBuilder(length);
1500        for (int i = 0; i < length; ++i) {
1501            char ch = s.charAt(i);
1502            if (ch >= '0' && ch <= '9') {
1503                ch += offsetToLocalizedDigits;
1504            }
1505            result.append(ch);
1506        }
1507        return result;
1508    }
1509
1510    /**
1511     * Inserts the grouping separator every 3 digits. DecimalFormat lets you configure grouping
1512     * size, but you can't access that from Formatter, and the default is every 3 digits.
1513     */
1514    private CharSequence insertGrouping(CharSequence s) {
1515        StringBuilder result = new StringBuilder(s.length() + s.length()/3);
1516
1517        // A leading '-' doesn't want to be included in the grouping.
1518        int digitsLength = s.length();
1519        int i = 0;
1520        if (s.charAt(0) == '-') {
1521            --digitsLength;
1522            ++i;
1523            result.append('-');
1524        }
1525
1526        // Append the digits that come before the first separator.
1527        int headLength = digitsLength % 3;
1528        if (headLength == 0) {
1529            headLength = 3;
1530        }
1531        result.append(s, i, i + headLength);
1532        i += headLength;
1533
1534        // Append the remaining groups.
1535        for (; i < s.length(); i += 3) {
1536            result.append(localeData.groupingSeparator);
1537            result.append(s, i, i + 3);
1538        }
1539        return result;
1540    }
1541
1542    private CharSequence transformFromBoolean() {
1543        CharSequence result;
1544        if (arg instanceof Boolean) {
1545            result = arg.toString();
1546        } else if (arg == null) {
1547            result = "false";
1548        } else {
1549            result = "true";
1550        }
1551        return padding(result, 0);
1552    }
1553
1554    private CharSequence transformFromHashCode() {
1555        CharSequence result;
1556        if (arg == null) {
1557            result = "null";
1558        } else {
1559            result = Integer.toHexString(arg.hashCode());
1560        }
1561        return padding(result, 0);
1562    }
1563
1564    private CharSequence transformFromString() {
1565        if (arg instanceof Formattable) {
1566            int flags = 0;
1567            if (formatToken.flagMinus) {
1568                flags |= FormattableFlags.LEFT_JUSTIFY;
1569            }
1570            if (formatToken.flagSharp) {
1571                flags |= FormattableFlags.ALTERNATE;
1572            }
1573            if (Character.isUpperCase(formatToken.getConversionType())) {
1574                flags |= FormattableFlags.UPPERCASE;
1575            }
1576            ((Formattable) arg).formatTo(this, flags, formatToken.getWidth(),
1577                    formatToken.getPrecision());
1578            // all actions have been taken out in the
1579            // Formattable.formatTo, thus there is nothing to do, just
1580            // returns null, which tells the Parser to add nothing to the
1581            // output.
1582            return null;
1583        }
1584        CharSequence result = arg != null ? arg.toString() : "null";
1585        return padding(result, 0);
1586    }
1587
1588    private CharSequence transformFromCharacter() {
1589        if (arg == null) {
1590            return padding("null", 0);
1591        }
1592        if (arg instanceof Character) {
1593            return padding(String.valueOf(arg), 0);
1594        } else if (arg instanceof Byte || arg instanceof Short || arg instanceof Integer) {
1595            int codePoint = ((Number) arg).intValue();
1596            if (!Character.isValidCodePoint(codePoint)) {
1597                throw new IllegalFormatCodePointException(codePoint);
1598            }
1599            CharSequence result = (codePoint < Character.MIN_SUPPLEMENTARY_CODE_POINT)
1600                    ? String.valueOf((char) codePoint)
1601                    : String.valueOf(Character.toChars(codePoint));
1602            return padding(result, 0);
1603        } else {
1604            throw badArgumentType();
1605        }
1606    }
1607
1608    private CharSequence transformFromPercent() {
1609        return padding("%", 0);
1610    }
1611
1612    private CharSequence padding(CharSequence source, int startIndex) {
1613        int start = startIndex;
1614        int width = formatToken.getWidth();
1615        int precision = formatToken.getPrecision();
1616
1617        int length = source.length();
1618        if (precision >= 0) {
1619            length = Math.min(length, precision);
1620            if (source instanceof StringBuilder) {
1621                ((StringBuilder) source).setLength(length);
1622            } else {
1623                source = source.subSequence(0, length);
1624            }
1625        }
1626        if (width > 0) {
1627            width = Math.max(source.length(), width);
1628        }
1629        if (length >= width) {
1630            return source;
1631        }
1632
1633        char paddingChar = '\u0020'; // space as padding char.
1634        if (formatToken.flagZero) {
1635            if (formatToken.getConversionType() == 'd') {
1636                paddingChar = localeData.zeroDigit;
1637            } else {
1638                paddingChar = '0'; // No localized digits for bases other than decimal.
1639            }
1640        } else {
1641            // if padding char is space, always pad from the start.
1642            start = 0;
1643        }
1644        char[] paddingChars = new char[width - length];
1645        Arrays.fill(paddingChars, paddingChar);
1646
1647        boolean paddingRight = formatToken.flagMinus;
1648        StringBuilder result = toStringBuilder(source);
1649        if (paddingRight) {
1650            result.append(paddingChars);
1651        } else {
1652            result.insert(start, paddingChars);
1653        }
1654        return result;
1655    }
1656
1657    private StringBuilder toStringBuilder(CharSequence cs) {
1658        return cs instanceof StringBuilder ? (StringBuilder) cs : new StringBuilder(cs);
1659    }
1660
1661    private StringBuilder wrapParentheses(StringBuilder result) {
1662        result.setCharAt(0, '('); // Replace the '-'.
1663        if (formatToken.flagZero) {
1664            formatToken.setWidth(formatToken.getWidth() - 1);
1665            result = (StringBuilder) padding(result, 1);
1666            result.append(')');
1667        } else {
1668            result.append(')');
1669            result = (StringBuilder) padding(result, 0);
1670        }
1671        return result;
1672    }
1673
1674    private CharSequence transformFromInteger() {
1675        int startIndex = 0;
1676        StringBuilder result = new StringBuilder();
1677        char currentConversionType = formatToken.getConversionType();
1678
1679        long value;
1680        if (arg instanceof Long) {
1681            value = ((Long) arg).longValue();
1682        } else if (arg instanceof Integer) {
1683            value = ((Integer) arg).longValue();
1684        } else if (arg instanceof Short) {
1685            value = ((Short) arg).longValue();
1686        } else if (arg instanceof Byte) {
1687            value = ((Byte) arg).longValue();
1688        } else {
1689            throw badArgumentType();
1690        }
1691
1692        if (formatToken.flagSharp) {
1693            if (currentConversionType == 'o') {
1694                result.append("0");
1695                startIndex += 1;
1696            } else {
1697                result.append("0x");
1698                startIndex += 2;
1699            }
1700        }
1701
1702        if (currentConversionType == 'd') {
1703            CharSequence digits = Long.toString(value);
1704            if (formatToken.flagComma) {
1705                digits = insertGrouping(digits);
1706            }
1707            if (localeData.zeroDigit != '0') {
1708                digits = localizeDigits(digits);
1709            }
1710            result.append(digits);
1711
1712            if (value < 0) {
1713                if (formatToken.flagParenthesis) {
1714                    return wrapParentheses(result);
1715                } else if (formatToken.flagZero) {
1716                    startIndex++;
1717                }
1718            } else {
1719                if (formatToken.flagPlus) {
1720                    result.insert(0, '+');
1721                    startIndex += 1;
1722                } else if (formatToken.flagSpace) {
1723                    result.insert(0, ' ');
1724                    startIndex += 1;
1725                }
1726            }
1727        } else {
1728            // Undo sign-extension, since we'll be using Long.to(Octal|Hex)String.
1729            if (arg instanceof Byte) {
1730                value &= 0xffL;
1731            } else if (arg instanceof Short) {
1732                value &= 0xffffL;
1733            } else if (arg instanceof Integer) {
1734                value &= 0xffffffffL;
1735            }
1736            if (currentConversionType == 'o') {
1737                result.append(Long.toOctalString(value));
1738            } else {
1739                result.append(Long.toHexString(value));
1740            }
1741        }
1742
1743        return padding(result, startIndex);
1744    }
1745
1746    private CharSequence transformFromNull() {
1747        formatToken.flagZero = false;
1748        return padding("null", 0);
1749    }
1750
1751    private CharSequence transformFromBigInteger() {
1752        int startIndex = 0;
1753        StringBuilder result = new StringBuilder();
1754        BigInteger bigInt = (BigInteger) arg;
1755        char currentConversionType = formatToken.getConversionType();
1756
1757        if (bigInt == null) {
1758            return transformFromNull();
1759        }
1760
1761        boolean isNegative = (bigInt.compareTo(BigInteger.ZERO) < 0);
1762
1763        if (currentConversionType == 'd') {
1764            CharSequence digits = bigInt.toString(10);
1765            if (formatToken.flagComma) {
1766                digits = insertGrouping(digits);
1767            }
1768            result.append(digits);
1769        } else if (currentConversionType == 'o') {
1770            // convert BigInteger to a string presentation using radix 8
1771            result.append(bigInt.toString(8));
1772        } else {
1773            // convert BigInteger to a string presentation using radix 16
1774            result.append(bigInt.toString(16));
1775        }
1776        if (formatToken.flagSharp) {
1777            startIndex = isNegative ? 1 : 0;
1778            if (currentConversionType == 'o') {
1779                result.insert(startIndex, "0");
1780                startIndex += 1;
1781            } else if (currentConversionType == 'x' || currentConversionType == 'X') {
1782                result.insert(startIndex, "0x");
1783                startIndex += 2;
1784            }
1785        }
1786
1787        if (!isNegative) {
1788            if (formatToken.flagPlus) {
1789                result.insert(0, '+');
1790                startIndex += 1;
1791            }
1792            if (formatToken.flagSpace) {
1793                result.insert(0, ' ');
1794                startIndex += 1;
1795            }
1796        }
1797
1798        /* pad paddingChar to the output */
1799        if (isNegative && formatToken.flagParenthesis) {
1800            return wrapParentheses(result);
1801        }
1802        if (isNegative && formatToken.flagZero) {
1803            startIndex++;
1804        }
1805        return padding(result, startIndex);
1806    }
1807
1808    private CharSequence transformFromDateTime() {
1809        if (arg == null) {
1810            return transformFromNull();
1811        }
1812
1813        Calendar calendar;
1814        if (arg instanceof Calendar) {
1815            calendar = (Calendar) arg;
1816        } else {
1817            Date date = null;
1818            if (arg instanceof Long) {
1819                date = new Date(((Long) arg).longValue());
1820            } else if (arg instanceof Date) {
1821                date = (Date) arg;
1822            } else {
1823                throw badArgumentType();
1824            }
1825            calendar = Calendar.getInstance(locale);
1826            calendar.setTime(date);
1827        }
1828
1829        StringBuilder result = new StringBuilder();
1830        if (!appendT(result, formatToken.getDateSuffix(), calendar)) {
1831            throw formatToken.unknownFormatConversionException();
1832        }
1833        return padding(result, 0);
1834    }
1835
1836    private boolean appendT(StringBuilder result, char conversion, Calendar calendar) {
1837        switch (conversion) {
1838        case 'A':
1839            result.append(localeData.longWeekdayNames[calendar.get(Calendar.DAY_OF_WEEK)]);
1840            return true;
1841        case 'a':
1842            result.append(localeData.shortWeekdayNames[calendar.get(Calendar.DAY_OF_WEEK)]);
1843            return true;
1844        case 'B':
1845            result.append(localeData.longMonthNames[calendar.get(Calendar.MONTH)]);
1846            return true;
1847        case 'b': case 'h':
1848            result.append(localeData.shortMonthNames[calendar.get(Calendar.MONTH)]);
1849            return true;
1850        case 'C':
1851            appendLocalized(result, calendar.get(Calendar.YEAR) / 100, 2);
1852            return true;
1853        case 'D':
1854            appendT(result, 'm', calendar);
1855            result.append('/');
1856            appendT(result, 'd', calendar);
1857            result.append('/');
1858            appendT(result, 'y', calendar);
1859            return true;
1860        case 'F':
1861            appendT(result, 'Y', calendar);
1862            result.append('-');
1863            appendT(result, 'm', calendar);
1864            result.append('-');
1865            appendT(result, 'd', calendar);
1866            return true;
1867        case 'H':
1868            appendLocalized(result, calendar.get(Calendar.HOUR_OF_DAY), 2);
1869            return true;
1870        case 'I':
1871            appendLocalized(result, to12Hour(calendar.get(Calendar.HOUR)), 2);
1872            return true;
1873        case 'L':
1874            appendLocalized(result, calendar.get(Calendar.MILLISECOND), 3);
1875            return true;
1876        case 'M':
1877            appendLocalized(result, calendar.get(Calendar.MINUTE), 2);
1878            return true;
1879        case 'N':
1880            appendLocalized(result, calendar.get(Calendar.MILLISECOND) * 1000000L, 9);
1881            return true;
1882        case 'Q':
1883            appendLocalized(result, calendar.getTimeInMillis(), 0);
1884            return true;
1885        case 'R':
1886            appendT(result, 'H', calendar);
1887            result.append(':');
1888            appendT(result, 'M', calendar);
1889            return true;
1890        case 'S':
1891            appendLocalized(result, calendar.get(Calendar.SECOND), 2);
1892            return true;
1893        case 'T':
1894            appendT(result, 'H', calendar);
1895            result.append(':');
1896            appendT(result, 'M', calendar);
1897            result.append(':');
1898            appendT(result, 'S', calendar);
1899            return true;
1900        case 'Y':
1901            appendLocalized(result, calendar.get(Calendar.YEAR), 4);
1902            return true;
1903        case 'Z':
1904            TimeZone timeZone = calendar.getTimeZone();
1905            result.append(timeZone.getDisplayName(timeZone.inDaylightTime(calendar.getTime()),
1906                    TimeZone.SHORT, locale));
1907            return true;
1908        case 'c':
1909            appendT(result, 'a', calendar);
1910            result.append(' ');
1911            appendT(result, 'b', calendar);
1912            result.append(' ');
1913            appendT(result, 'd', calendar);
1914            result.append(' ');
1915            appendT(result, 'T', calendar);
1916            result.append(' ');
1917            appendT(result, 'Z', calendar);
1918            result.append(' ');
1919            appendT(result, 'Y', calendar);
1920            return true;
1921        case 'd':
1922            appendLocalized(result, calendar.get(Calendar.DAY_OF_MONTH), 2);
1923            return true;
1924        case 'e':
1925            appendLocalized(result, calendar.get(Calendar.DAY_OF_MONTH), 0);
1926            return true;
1927        case 'j':
1928            appendLocalized(result, calendar.get(Calendar.DAY_OF_YEAR), 3);
1929            return true;
1930        case 'k':
1931            appendLocalized(result, calendar.get(Calendar.HOUR_OF_DAY), 0);
1932            return true;
1933        case 'l':
1934            appendLocalized(result, to12Hour(calendar.get(Calendar.HOUR)), 0);
1935            return true;
1936        case 'm':
1937            // Calendar.JANUARY is 0; humans want January represented as 1.
1938            appendLocalized(result, calendar.get(Calendar.MONTH) + 1, 2);
1939            return true;
1940        case 'p':
1941            result.append(localeData.amPm[calendar.get(Calendar.AM_PM)].toLowerCase(locale));
1942            return true;
1943        case 'r':
1944            appendT(result, 'I', calendar);
1945            result.append(':');
1946            appendT(result, 'M', calendar);
1947            result.append(':');
1948            appendT(result, 'S', calendar);
1949            result.append(' ');
1950            result.append(localeData.amPm[calendar.get(Calendar.AM_PM)]);
1951            return true;
1952        case 's':
1953            appendLocalized(result, calendar.getTimeInMillis() / 1000, 0);
1954            return true;
1955        case 'y':
1956            appendLocalized(result, calendar.get(Calendar.YEAR) % 100, 2);
1957            return true;
1958        case 'z':
1959            long offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
1960            char sign = '+';
1961            if (offset < 0) {
1962                sign = '-';
1963                offset = -offset;
1964            }
1965            result.append(sign);
1966            appendLocalized(result, offset / 3600000, 2);
1967            appendLocalized(result, (offset % 3600000) / 60000, 2);
1968            return true;
1969        }
1970        return false;
1971    }
1972
1973    private int to12Hour(int hour) {
1974        return hour == 0 ? 12 : hour;
1975    }
1976
1977    private void appendLocalized(StringBuilder result, long value, int width) {
1978        int paddingIndex = result.length();
1979        char zeroDigit = localeData.zeroDigit;
1980        if (zeroDigit == '0') {
1981            result.append(value);
1982        } else {
1983            result.append(localizeDigits(Long.toString(value)));
1984        }
1985        int zeroCount = width - (result.length() - paddingIndex);
1986        if (zeroCount <= 0) {
1987            return;
1988        }
1989        if (zeroDigit == '0') {
1990            result.insert(paddingIndex, ZEROS, 0, zeroCount);
1991        } else {
1992            for (int i = 0; i < zeroCount; ++i) {
1993                result.insert(paddingIndex, zeroDigit);
1994            }
1995        }
1996    }
1997
1998    private CharSequence transformFromSpecialNumber(double d) {
1999        String source = null;
2000        if (Double.isNaN(d)) {
2001            source = "NaN";
2002        } else if (d == Double.POSITIVE_INFINITY) {
2003            if (formatToken.flagPlus) {
2004                source = "+Infinity";
2005            } else if (formatToken.flagSpace) {
2006                source = " Infinity";
2007            } else {
2008                source = "Infinity";
2009            }
2010        } else if (d == Double.NEGATIVE_INFINITY) {
2011            if (formatToken.flagParenthesis) {
2012                source = "(Infinity)";
2013            } else {
2014                source = "-Infinity";
2015            }
2016        } else {
2017            return null;
2018        }
2019
2020        formatToken.setPrecision(FormatToken.UNSET);
2021        formatToken.flagZero = false;
2022        return padding(source, 0);
2023    }
2024
2025    private CharSequence transformFromFloat() {
2026        if (arg == null) {
2027            return transformFromNull();
2028        } else if (arg instanceof Float || arg instanceof Double) {
2029            Number number = (Number) arg;
2030            double d = number.doubleValue();
2031            if (d != d || d == Double.POSITIVE_INFINITY || d == Double.NEGATIVE_INFINITY) {
2032                return transformFromSpecialNumber(d);
2033            }
2034        } else if (arg instanceof BigDecimal) {
2035            // BigDecimal can't represent NaN or infinities, but its doubleValue method will return
2036            // infinities if the BigDecimal is too big for a double.
2037        } else {
2038            throw badArgumentType();
2039        }
2040
2041        char conversionType = formatToken.getConversionType();
2042        if (conversionType != 'a' && conversionType != 'A' && !formatToken.isPrecisionSet()) {
2043            formatToken.setPrecision(FormatToken.DEFAULT_PRECISION);
2044        }
2045
2046        StringBuilder result = new StringBuilder();
2047        switch (conversionType) {
2048        case 'a': case 'A':
2049            transformA(result);
2050            break;
2051        case 'e': case 'E':
2052            transformE(result);
2053            break;
2054        case 'f':
2055            transformF(result);
2056            break;
2057        case 'g':
2058        case 'G':
2059            transformG(result);
2060            break;
2061        default:
2062            throw formatToken.unknownFormatConversionException();
2063        }
2064
2065        formatToken.setPrecision(FormatToken.UNSET);
2066
2067        int startIndex = 0;
2068        if (startsWithMinusSign(result, localeData.minusSign)) {
2069            if (formatToken.flagParenthesis) {
2070                return wrapParentheses(result);
2071            }
2072        } else {
2073            if (formatToken.flagSpace) {
2074                result.insert(0, ' ');
2075                startIndex++;
2076            }
2077            if (formatToken.flagPlus) {
2078                result.insert(0, '+');
2079                startIndex++;
2080            }
2081        }
2082
2083        char firstChar = result.charAt(0);
2084        if (formatToken.flagZero && (firstChar == '+' ||
2085                startsWithMinusSign(result, localeData.minusSign))) {
2086            startIndex = localeData.minusSign.length();
2087        }
2088
2089        if (conversionType == 'a' || conversionType == 'A') {
2090            startIndex += 2;
2091        }
2092        return padding(result, startIndex);
2093    }
2094
2095    private static boolean startsWithMinusSign(CharSequence cs, String minusSign) {
2096        if (cs.length() < minusSign.length()) {
2097            return false;
2098        }
2099
2100        for (int i = 0; i < minusSign.length(); ++i) {
2101            if (minusSign.charAt(i) != cs.charAt(i)) {
2102                return false;
2103            }
2104        }
2105
2106        return true;
2107    }
2108
2109    private void transformE(StringBuilder result) {
2110        // All zeros in this method are *pattern* characters, so no localization.
2111        final int precision = formatToken.getPrecision();
2112        String pattern = "0E+00";
2113        if (precision > 0) {
2114            StringBuilder sb = new StringBuilder("0.");
2115            char[] zeros = new char[precision];
2116            Arrays.fill(zeros, '0');
2117            sb.append(zeros);
2118            sb.append("E+00");
2119            pattern = sb.toString();
2120        }
2121
2122        NativeDecimalFormat nf = getDecimalFormat(pattern);
2123        char[] chars;
2124        if (arg instanceof BigDecimal) {
2125            chars = nf.formatBigDecimal((BigDecimal) arg, null);
2126        } else {
2127            chars = nf.formatDouble(((Number) arg).doubleValue(), null);
2128        }
2129        // Unlike %f, %e uses 'e' (regardless of what the DecimalFormatSymbols would have us use).
2130        for (int i = 0; i < chars.length; ++i) {
2131            if (chars[i] == 'E') {
2132                chars[i] = 'e';
2133            }
2134        }
2135        result.append(chars);
2136        // The # flag requires that we always output a decimal separator.
2137        if (formatToken.flagSharp && precision == 0) {
2138            int indexOfE = result.indexOf("e");
2139            result.insert(indexOfE, localeData.decimalSeparator);
2140        }
2141    }
2142
2143    private void transformG(StringBuilder result) {
2144        int precision = formatToken.getPrecision();
2145        if (precision == 0) {
2146            precision = 1;
2147        }
2148        formatToken.setPrecision(precision);
2149
2150        double d = ((Number) arg).doubleValue();
2151        if (d == 0.0) {
2152            precision--;
2153            formatToken.setPrecision(precision);
2154            transformF(result);
2155            return;
2156        }
2157
2158        boolean requireScientificRepresentation = true;
2159        d = Math.abs(d);
2160        if (Double.isInfinite(d)) {
2161            precision = formatToken.getPrecision();
2162            precision--;
2163            formatToken.setPrecision(precision);
2164            transformE(result);
2165            return;
2166        }
2167        BigDecimal b = new BigDecimal(d, new MathContext(precision));
2168        d = b.doubleValue();
2169        long l = b.longValue();
2170
2171        if (d >= 1 && d < Math.pow(10, precision)) {
2172            if (l < Math.pow(10, precision)) {
2173                requireScientificRepresentation = false;
2174                precision -= String.valueOf(l).length();
2175                precision = precision < 0 ? 0 : precision;
2176                l = Math.round(d * Math.pow(10, precision + 1));
2177                if (String.valueOf(l).length() <= formatToken.getPrecision()) {
2178                    precision++;
2179                }
2180                formatToken.setPrecision(precision);
2181            }
2182        } else {
2183            l = b.movePointRight(4).longValue();
2184            if (d >= Math.pow(10, -4) && d < 1) {
2185                requireScientificRepresentation = false;
2186                precision += 4 - String.valueOf(l).length();
2187                l = b.movePointRight(precision + 1).longValue();
2188                if (String.valueOf(l).length() <= formatToken.getPrecision()) {
2189                    precision++;
2190                }
2191                l = b.movePointRight(precision).longValue();
2192                if (l >= Math.pow(10, precision - 4)) {
2193                    formatToken.setPrecision(precision);
2194                }
2195            }
2196        }
2197        if (requireScientificRepresentation) {
2198            precision = formatToken.getPrecision();
2199            precision--;
2200            formatToken.setPrecision(precision);
2201            transformE(result);
2202        } else {
2203            transformF(result);
2204        }
2205    }
2206
2207    private void transformF(StringBuilder result) {
2208        // All zeros in this method are *pattern* characters, so no localization.
2209        String pattern = "0.000000";
2210        final int precision = formatToken.getPrecision();
2211        if (formatToken.flagComma || precision != FormatToken.DEFAULT_PRECISION) {
2212            StringBuilder patternBuilder = new StringBuilder();
2213            if (formatToken.flagComma) {
2214                patternBuilder.append(',');
2215                int groupingSize = 3;
2216                char[] sharps = new char[groupingSize - 1];
2217                Arrays.fill(sharps, '#');
2218                patternBuilder.append(sharps);
2219            }
2220            patternBuilder.append('0');
2221            if (precision > 0) {
2222                patternBuilder.append('.');
2223                for (int i = 0; i < precision; ++i) {
2224                    patternBuilder.append('0');
2225                }
2226            }
2227            pattern = patternBuilder.toString();
2228        }
2229
2230        NativeDecimalFormat nf = getDecimalFormat(pattern);
2231        if (arg instanceof BigDecimal) {
2232            result.append(nf.formatBigDecimal((BigDecimal) arg, null));
2233        } else {
2234            result.append(nf.formatDouble(((Number) arg).doubleValue(), null));
2235        }
2236        // The # flag requires that we always output a decimal separator.
2237        if (formatToken.flagSharp && precision == 0) {
2238            result.append(localeData.decimalSeparator);
2239        }
2240    }
2241
2242    private void transformA(StringBuilder result) {
2243        if (arg instanceof Float) {
2244            result.append(Float.toHexString(((Float) arg).floatValue()));
2245        } else if (arg instanceof Double) {
2246            result.append(Double.toHexString(((Double) arg).doubleValue()));
2247        } else {
2248            throw badArgumentType();
2249        }
2250
2251        if (!formatToken.isPrecisionSet()) {
2252            return;
2253        }
2254
2255        int precision = formatToken.getPrecision();
2256        if (precision == 0) {
2257            precision = 1;
2258        }
2259        int indexOfFirstFractionalDigit = result.indexOf(".") + 1;
2260        int indexOfP = result.indexOf("p");
2261        int fractionalLength = indexOfP - indexOfFirstFractionalDigit;
2262
2263        if (fractionalLength == precision) {
2264            return;
2265        }
2266
2267        if (fractionalLength < precision) {
2268            char[] zeros = new char[precision - fractionalLength];
2269            Arrays.fill(zeros, '0'); // %a shouldn't be localized.
2270            result.insert(indexOfP, zeros);
2271            return;
2272        }
2273        result.delete(indexOfFirstFractionalDigit + precision, indexOfP);
2274    }
2275
2276    private static class FormatSpecifierParser {
2277        private String format;
2278        private int length;
2279
2280        private int startIndex;
2281        private int i;
2282
2283        /**
2284         * Constructs a new parser for the given format string.
2285         */
2286        FormatSpecifierParser(String format) {
2287            this.format = format;
2288            this.length = format.length();
2289        }
2290
2291        /**
2292         * Returns a FormatToken representing the format specifier starting at 'offset'.
2293         * @param offset the first character after the '%'
2294         */
2295        FormatToken parseFormatToken(int offset) {
2296            this.startIndex = offset;
2297            this.i = offset;
2298            return parseArgumentIndexAndFlags(new FormatToken());
2299        }
2300
2301        /**
2302         * Returns a string corresponding to the last format specifier that was parsed.
2303         * Used to construct error messages.
2304         */
2305        String getFormatSpecifierText() {
2306            return format.substring(startIndex, i);
2307        }
2308
2309        private int peek() {
2310            return (i < length) ? format.charAt(i) : -1;
2311        }
2312
2313        private char advance() {
2314            if (i >= length) {
2315                throw unknownFormatConversionException();
2316            }
2317            return format.charAt(i++);
2318        }
2319
2320        private UnknownFormatConversionException unknownFormatConversionException() {
2321            throw new UnknownFormatConversionException(getFormatSpecifierText());
2322        }
2323
2324        private FormatToken parseArgumentIndexAndFlags(FormatToken token) {
2325            // Parse the argument index, if there is one.
2326            int position = i;
2327            int ch = peek();
2328            if (Character.isDigit(ch)) {
2329                int number = nextInt();
2330                if (peek() == '$') {
2331                    // The number was an argument index.
2332                    advance(); // Swallow the '$'.
2333                    if (number == FormatToken.UNSET) {
2334                        throw new MissingFormatArgumentException(getFormatSpecifierText());
2335                    }
2336                    // k$ stands for the argument whose index is k-1 except that
2337                    // 0$ and 1$ both stand for the first element.
2338                    token.setArgIndex(Math.max(0, number - 1));
2339                } else {
2340                    if (ch == '0') {
2341                        // The digit zero is a format flag, so reparse it as such.
2342                        i = position;
2343                    } else {
2344                        // The number was a width. This means there are no flags to parse.
2345                        return parseWidth(token, number);
2346                    }
2347                }
2348            } else if (ch == '<') {
2349                token.setArgIndex(FormatToken.LAST_ARGUMENT_INDEX);
2350                advance();
2351            }
2352
2353            // Parse the flags.
2354            while (token.setFlag(peek())) {
2355                advance();
2356            }
2357
2358            // What comes next?
2359            ch = peek();
2360            if (Character.isDigit(ch)) {
2361                return parseWidth(token, nextInt());
2362            } else if (ch == '.') {
2363                return parsePrecision(token);
2364            } else {
2365                return parseConversionType(token);
2366            }
2367        }
2368
2369        // We pass the width in because in some cases we've already parsed it.
2370        // (Because of the ambiguity between argument indexes and widths.)
2371        private FormatToken parseWidth(FormatToken token, int width) {
2372            token.setWidth(width);
2373            int ch = peek();
2374            if (ch == '.') {
2375                return parsePrecision(token);
2376            } else {
2377                return parseConversionType(token);
2378            }
2379        }
2380
2381        private FormatToken parsePrecision(FormatToken token) {
2382            advance(); // Swallow the '.'.
2383            int ch = peek();
2384            if (Character.isDigit(ch)) {
2385                token.setPrecision(nextInt());
2386                return parseConversionType(token);
2387            } else {
2388                // The precision is required but not given by the format string.
2389                throw unknownFormatConversionException();
2390            }
2391        }
2392
2393        private FormatToken parseConversionType(FormatToken token) {
2394            char conversionType = advance(); // A conversion type is mandatory.
2395            token.setConversionType(conversionType);
2396            if (conversionType == 't' || conversionType == 'T') {
2397                char dateSuffix = advance(); // A date suffix is mandatory for 't' or 'T'.
2398                token.setDateSuffix(dateSuffix);
2399            }
2400            return token;
2401        }
2402
2403        // Parses an integer (of arbitrary length, but typically just one digit).
2404        private int nextInt() {
2405            long value = 0;
2406            while (i < length && Character.isDigit(format.charAt(i))) {
2407                value = 10 * value + (format.charAt(i++) - '0');
2408                if (value > Integer.MAX_VALUE) {
2409                    return failNextInt();
2410                }
2411            }
2412            return (int) value;
2413        }
2414
2415        // Swallow remaining digits to resync our attempted parse, but return failure.
2416        private int failNextInt() {
2417            while (Character.isDigit(peek())) {
2418                advance();
2419            }
2420            return FormatToken.UNSET;
2421        }
2422    }
2423}
2424