History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/text (120 of 18352 files). Show all

Unified · Split

120 files
  1. java/pkg/java/text/Annotation.class +0 −0
  2. java/pkg/java/text/Annotation.java +84 −0
  3. java/pkg/java/text/AttributeEntry.class +0 −0
  4. java/pkg/java/text/AttributedCharacterIterator$Attribute.class +0 −0
  5. java/pkg/java/text/AttributedCharacterIterator.class +0 −0
  6. java/pkg/java/text/AttributedCharacterIterator.java +254 −0
  7. java/pkg/java/text/AttributedString$AttributeMap.class +0 −0
  8. java/pkg/java/text/AttributedString$AttributedStringIterator.class +0 −0
  9. java/pkg/java/text/AttributedString.class +0 −0
  10. java/pkg/java/text/AttributedString.java +1120 −0
  11. java/pkg/java/text/Bidi.class +0 −0
  12. java/pkg/java/text/Bidi.java +328 −0
  13. java/pkg/java/text/BreakDictionary$1.class +0 −0
  14. java/pkg/java/text/BreakDictionary.class +0 −0
  15. java/pkg/java/text/BreakDictionary.java +341 −0
  16. java/pkg/java/text/BreakIterator$1.class +0 −0
  17. java/pkg/java/text/BreakIterator$BreakIteratorCache.class +0 −0
  18. java/pkg/java/text/BreakIterator$BreakIteratorGetter.class +0 −0
  19. java/pkg/java/text/BreakIterator.class +0 −0
  20. java/pkg/java/text/BreakIterator.java +715 −0
  21. java/pkg/java/text/CalendarBuilder.class +0 −0
  22. java/pkg/java/text/CalendarBuilder.java +170 −0
  23. java/pkg/java/text/CharacterIterator.class +0 −0
  24. java/pkg/java/text/CharacterIterator.java +193 −0
  25. java/pkg/java/text/CharacterIteratorFieldDelegate.class +0 −0
  26. java/pkg/java/text/CharacterIteratorFieldDelegate.java +124 −0
  27. java/pkg/java/text/ChoiceFormat.class +0 −0
  28. java/pkg/java/text/ChoiceFormat.java +619 −0
  29. java/pkg/java/text/CollationElementIterator.class +0 −0
  30. java/pkg/java/text/CollationElementIterator.java +777 −0
  31. java/pkg/java/text/CollationKey.class +0 −0
  32. java/pkg/java/text/CollationKey.java +145 −0
  33. java/pkg/java/text/CollationRules.class +0 −0
  34. java/pkg/java/text/CollationRules.java +274 −0
  35. java/pkg/java/text/Collator$CollatorGetter.class +0 −0
  36. java/pkg/java/text/Collator.class +0 −0
  37. java/pkg/java/text/Collator.java +553 −0
  38. java/pkg/java/text/DateFormat$DateFormatGetter.class +0 −0
  39. java/pkg/java/text/DateFormat$Field.class +0 −0
  40. java/pkg/java/text/DateFormat.class +0 −0
  41. java/pkg/java/text/DateFormat.java +1030 −0
  42. java/pkg/java/text/DateFormatSymbols$DateFormatSymbolsGetter.class +0 −0
  43. java/pkg/java/text/DateFormatSymbols.class +0 −0
  44. java/pkg/java/text/DateFormatSymbols.java +794 −0
  45. java/pkg/java/text/DecimalFormat.class +0 −0
  46. java/pkg/java/text/DecimalFormat.java +3278 −0
  47. java/pkg/java/text/DecimalFormatSymbols$DecimalFormatSymbolsGetter.class +0 −0
  48. java/pkg/java/text/DecimalFormatSymbols.class +0 −0
  49. java/pkg/java/text/DecimalFormatSymbols.java +837 −0
  50. java/pkg/java/text/DictionaryBasedBreakIterator.class +0 −0
  51. java/pkg/java/text/DictionaryBasedBreakIterator.java +514 −0
  52. java/pkg/java/text/DigitList$1.class +0 −0
  53. java/pkg/java/text/DigitList.class +0 −0
  54. java/pkg/java/text/DigitList.java +715 −0
  55. java/pkg/java/text/DontCareFieldPosition$1.class +0 −0
  56. java/pkg/java/text/DontCareFieldPosition.class +0 −0
  57. java/pkg/java/text/DontCareFieldPosition.java +53 −0
  58. java/pkg/java/text/EntryPair.class +0 −0
  59. java/pkg/java/text/EntryPair.java +60 −0
  60. java/pkg/java/text/FieldPosition$1.class +0 −0
  61. java/pkg/java/text/FieldPosition$Delegate.class +0 −0
  62. java/pkg/java/text/FieldPosition.class +0 −0
  63. java/pkg/java/text/FieldPosition.java +303 −0
  64. java/pkg/java/text/Format$Field.class +0 −0
  65. java/pkg/java/text/Format$FieldDelegate.class +0 −0
  66. java/pkg/java/text/Format.class +0 −0
  67. java/pkg/java/text/Format.java +406 −0
  68. java/pkg/java/text/MergeCollation.class +0 −0
  69. java/pkg/java/text/MergeCollation.java +342 −0
  70. java/pkg/java/text/MessageFormat$Field.class +0 −0
  71. java/pkg/java/text/MessageFormat.class +0 −0
  72. java/pkg/java/text/MessageFormat.java +1594 −0
  73. java/pkg/java/text/Normalizer$Form.class +0 −0
  74. java/pkg/java/text/Normalizer.class +0 −0
  75. java/pkg/java/text/Normalizer.java +183 −0
  76. java/pkg/java/text/NumberFormat$Field.class +0 −0
  77. java/pkg/java/text/NumberFormat$NumberFormatGetter.class +0 −0
  78. java/pkg/java/text/NumberFormat.class +0 −0
  79. java/pkg/java/text/NumberFormat.java +1162 −0
  80. java/pkg/java/text/ParseException.class +0 −0
  81. java/pkg/java/text/ParseException.java +78 −0
  82. java/pkg/java/text/ParsePosition.class +0 −0
  83. java/pkg/java/text/ParsePosition.java +139 −0
  84. java/pkg/java/text/PatternEntry$Parser.class +0 −0
  85. java/pkg/java/text/PatternEntry.class +0 −0
  86. java/pkg/java/text/PatternEntry.java +306 −0
  87. java/pkg/java/text/RBCollationTables$1.class +0 −0
  88. java/pkg/java/text/RBCollationTables$BuildAPI.class +0 −0
  89. java/pkg/java/text/RBCollationTables.class +0 −0
  90. java/pkg/java/text/RBCollationTables.java +303 −0
  91. java/pkg/java/text/RBTableBuilder.class +0 −0
  92. java/pkg/java/text/RBTableBuilder.java +618 −0
  93. java/pkg/java/text/RuleBasedBreakIterator$1.class +0 −0
  94. java/pkg/java/text/RuleBasedBreakIterator$SafeCharIterator.class +0 −0
  95. java/pkg/java/text/RuleBasedBreakIterator.class +0 −0
  96. java/pkg/java/text/RuleBasedBreakIterator.java +1148 −0
  97. java/pkg/java/text/RuleBasedCollationKey.class +0 −0
  98. java/pkg/java/text/RuleBasedCollationKey.java +123 −0
  99. java/pkg/java/text/RuleBasedCollator.class +0 −0
  100. java/pkg/java/text/RuleBasedCollator.java +763 −0
  101. java/pkg/java/text/SimpleDateFormat.class +0 −0
  102. java/pkg/java/text/SimpleDateFormat.java +2350 −0
  103. java/pkg/java/text/StringCharacterIterator.class +0 −0
  104. java/pkg/java/text/StringCharacterIterator.java +279 −0
  105. java/pkg/java/text/mkfile +49 −0
  106. java/pkg/java/text/package.html +65 −0
  107. java/pkg/java/text/spi/BreakIteratorProvider.class +0 −0
  108. java/pkg/java/text/spi/BreakIteratorProvider.java +107 −0
  109. java/pkg/java/text/spi/CollatorProvider.class +0 −0
  110. java/pkg/java/text/spi/CollatorProvider.java +61 −0
  111. java/pkg/java/text/spi/DateFormatProvider.class +0 −0
  112. java/pkg/java/text/spi/DateFormatProvider.java +114 −0
  113. java/pkg/java/text/spi/DateFormatSymbolsProvider.class +0 −0
  114. java/pkg/java/text/spi/DateFormatSymbolsProvider.java +62 −0
  115. java/pkg/java/text/spi/DecimalFormatSymbolsProvider.class +0 −0
  116. java/pkg/java/text/spi/DecimalFormatSymbolsProvider.java +62 −0
  117. java/pkg/java/text/spi/NumberFormatProvider.class +0 −0
  118. java/pkg/java/text/spi/NumberFormatProvider.java +113 −0
  119. java/pkg/java/text/spi/mkfile +13 −0
  120. java/pkg/java/text/spi/package.html +50 −0
java/pkg/java/text/Annotation.class+0−0

Binary file not shown.

java/pkg/java/text/Annotation.java+84−0
@@ -0,0 +1,84 @@
1+/*
2+ * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.text;
27+
28+/**
29+* An Annotation object is used as a wrapper for a text attribute value if
30+* the attribute has annotation characteristics. These characteristics are:
31+* <ul>
32+* <li>The text range that the attribute is applied to is critical to the
33+* semantics of the range. That means, the attribute cannot be applied to subranges
34+* of the text range that it applies to, and, if two adjacent text ranges have
35+* the same value for this attribute, the attribute still cannot be applied to
36+* the combined range as a whole with this value.
37+* <li>The attribute or its value usually do no longer apply if the underlying text is
38+* changed.
39+* </ul>
40+*
41+* An example is grammatical information attached to a sentence:
42+* For the previous sentence, you can say that "an example"
43+* is the subject, but you cannot say the same about "an", "example", or "exam".
44+* When the text is changed, the grammatical information typically becomes invalid.
45+* Another example is Japanese reading information (yomi).
46+*
47+* <p>
48+* Wrapping the attribute value into an Annotation object guarantees that
49+* adjacent text runs don't get merged even if the attribute values are equal,
50+* and indicates to text containers that the attribute should be discarded if
51+* the underlying text is modified.
52+*
53+* @see AttributedCharacterIterator
54+* @since 1.2
55+*/
56+
57+public class Annotation {
58+
59+ /**
60+ * Constructs an annotation record with the given value, which
61+ * may be null.
62+ * @param value The value of the attribute
63+ */
64+ public Annotation(Object value) {
65+ this.value = value;
66+ }
67+
68+ /**
69+ * Returns the value of the attribute, which may be null.
70+ */
71+ public Object getValue() {
72+ return value;
73+ }
74+
75+ /**
76+ * Returns the String representation of this Annotation.
77+ */
78+ public String toString() {
79+ return getClass().getName() + "[value=" + value + "]";
80+ }
81+
82+ private Object value;
83+
84+};
java/pkg/java/text/AttributeEntry.class+0−0

Binary file not shown.

java/pkg/java/text/AttributedCharacterIterator$Attribute.class+0−0

Binary file not shown.

java/pkg/java/text/AttributedCharacterIterator.class+0−0

Binary file not shown.

java/pkg/java/text/AttributedCharacterIterator.java+254−0
@@ -0,0 +1,254 @@
1+/*
2+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.text;
27+
28+import java.io.InvalidObjectException;
29+import java.io.Serializable;
30+import java.util.HashMap;
31+import java.util.Map;
32+import java.util.Set;
33+
34+/**
35+ * An {@code AttributedCharacterIterator} allows iteration through both text and
36+ * related attribute information.
37+ *
38+ * <p>
39+ * An attribute is a key/value pair, identified by the key. No two
40+ * attributes on a given character can have the same key.
41+ *
42+ * <p>The values for an attribute are immutable, or must not be mutated
43+ * by clients or storage. They are always passed by reference, and not
44+ * cloned.
45+ *
46+ * <p>A <em>run with respect to an attribute</em> is a maximum text range for
47+ * which:
48+ * <ul>
49+ * <li>the attribute is undefined or {@code null} for the entire range, or
50+ * <li>the attribute value is defined and has the same non-{@code null} value for the
51+ * entire range.
52+ * </ul>
53+ *
54+ * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
55+ * which this condition is met for each member attribute.
56+ *
57+ * <p>When getting a run with no explicit attributes specified (i.e.,
58+ * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
59+ * contiguous text segments having the same attributes (the same set
60+ * of attribute/value pairs) are treated as separate runs if the
61+ * attributes have been given to those text segments separately.
62+ *
63+ * <p>The returned indexes are limited to the range of the iterator.
64+ *
65+ * <p>The returned attribute information is limited to runs that contain
66+ * the current character.
67+ *
68+ * <p>
69+ * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
70+ * subclasses, such as {@link java.awt.font.TextAttribute}.
71+ *
72+ * @see AttributedCharacterIterator.Attribute
73+ * @see java.awt.font.TextAttribute
74+ * @see AttributedString
75+ * @see Annotation
76+ * @since 1.2
77+ */
78+
79+public interface AttributedCharacterIterator extends CharacterIterator {
80+
81+ /**
82+ * Defines attribute keys that are used to identify text attributes. These
83+ * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
84+ * @see AttributedCharacterIterator
85+ * @see AttributedString
86+ * @since 1.2
87+ */
88+
89+ public static class Attribute implements Serializable {
90+
91+ /**
92+ * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
93+ * to look up the corresponding predefined instance when deserializing
94+ * an instance.
95+ * @serial
96+ */
97+ private String name;
98+
99+ // table of all instances in this class, used by readResolve
100+ private static final Map instanceMap = new HashMap(7);
101+
102+ /**
103+ * Constructs an {@code Attribute} with the given name.
104+ */
105+ protected Attribute(String name) {
106+ this.name = name;
107+ if (this.getClass() == Attribute.class) {
108+ instanceMap.put(name, this);
109+ }
110+ }
111+
112+ /**
113+ * Compares two objects for equality. This version only returns true
114+ * for <code>x.equals(y)</code> if <code>x</code> and <code>y</code> refer
115+ * to the same object, and guarantees this for all subclasses.
116+ */
117+ public final boolean equals(Object obj) {
118+ return super.equals(obj);
119+ }
120+
121+ /**
122+ * Returns a hash code value for the object. This version is identical to
123+ * the one in {@code Object}, but is also final.
124+ */
125+ public final int hashCode() {
126+ return super.hashCode();
127+ }
128+
129+ /**
130+ * Returns a string representation of the object. This version returns the
131+ * concatenation of class name, {@code "("}, a name identifying the attribute
132+ * and {@code ")"}.
133+ */
134+ public String toString() {
135+ return getClass().getName() + "(" + name + ")";
136+ }
137+
138+ /**
139+ * Returns the name of the attribute.
140+ */
141+ protected String getName() {
142+ return name;
143+ }
144+
145+ /**
146+ * Resolves instances being deserialized to the predefined constants.
147+ */
148+ protected Object readResolve() throws InvalidObjectException {
149+ if (this.getClass() != Attribute.class) {
150+ throw new InvalidObjectException("subclass didn't correctly implement readResolve");
151+ }
152+
153+ Attribute instance = (Attribute) instanceMap.get(getName());
154+ if (instance != null) {
155+ return instance;
156+ } else {
157+ throw new InvalidObjectException("unknown attribute name");
158+ }
159+ }
160+
161+ /**
162+ * Attribute key for the language of some text.
163+ * <p> Values are instances of {@link java.util.Locale Locale}.
164+ * @see java.util.Locale
165+ */
166+ public static final Attribute LANGUAGE = new Attribute("language");
167+
168+ /**
169+ * Attribute key for the reading of some text. In languages where the written form
170+ * and the pronunciation of a word are only loosely related (such as Japanese),
171+ * it is often necessary to store the reading (pronunciation) along with the
172+ * written form.
173+ * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
174+ * @see Annotation
175+ * @see java.lang.String
176+ */
177+ public static final Attribute READING = new Attribute("reading");
178+
179+ /**
180+ * Attribute key for input method segments. Input methods often break
181+ * up text into segments, which usually correspond to words.
182+ * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
183+ * @see Annotation
184+ */
185+ public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
186+
187+ // make sure the serial version doesn't change between compiler versions
188+ private static final long serialVersionUID = -9142742483513960612L;
189+
190+ };
191+
192+ /**
193+ * Returns the index of the first character of the run
194+ * with respect to all attributes containing the current character.
195+ *
196+ * <p>Any contiguous text segments having the same attributes (the
197+ * same set of attribute/value pairs) are treated as separate runs
198+ * if the attributes have been given to those text segments separately.
199+ */
200+ public int getRunStart();
201+
202+ /**
203+ * Returns the index of the first character of the run
204+ * with respect to the given {@code attribute} containing the current character.
205+ */
206+ public int getRunStart(Attribute attribute);
207+
208+ /**
209+ * Returns the index of the first character of the run
210+ * with respect to the given {@code attributes} containing the current character.
211+ */
212+ public int getRunStart(Set<? extends Attribute> attributes);
213+
214+ /**
215+ * Returns the index of the first character following the run
216+ * with respect to all attributes containing the current character.
217+ *
218+ * <p>Any contiguous text segments having the same attributes (the
219+ * same set of attribute/value pairs) are treated as separate runs
220+ * if the attributes have been given to those text segments separately.
221+ */
222+ public int getRunLimit();
223+
224+ /**
225+ * Returns the index of the first character following the run
226+ * with respect to the given {@code attribute} containing the current character.
227+ */
228+ public int getRunLimit(Attribute attribute);
229+
230+ /**
231+ * Returns the index of the first character following the run
232+ * with respect to the given {@code attributes} containing the current character.
233+ */
234+ public int getRunLimit(Set<? extends Attribute> attributes);
235+
236+ /**
237+ * Returns a map with the attributes defined on the current
238+ * character.
239+ */
240+ public Map<Attribute,Object> getAttributes();
241+
242+ /**
243+ * Returns the value of the named {@code attribute} for the current character.
244+ * Returns {@code null} if the {@code attribute} is not defined.
245+ */
246+ public Object getAttribute(Attribute attribute);
247+
248+ /**
249+ * Returns the keys of all attributes defined on the
250+ * iterator's text range. The set is empty if no
251+ * attributes are defined.
252+ */
253+ public Set<Attribute> getAllAttributeKeys();
254+};
java/pkg/java/text/AttributedString$AttributeMap.class+0−0

Binary file not shown.

java/pkg/java/text/AttributedString$AttributedStringIterator.class+0−0

Binary file not shown.

java/pkg/java/text/AttributedString.class+0−0

Binary file not shown.

java/pkg/java/text/AttributedString.java+1120−0
@@ -0,0 +1,1120 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.text;
27+
28+import java.util.*;
29+import java.text.AttributedCharacterIterator.Attribute;
30+
31+/**
32+ * An AttributedString holds text and related attribute information. It
33+ * may be used as the actual data storage in some cases where a text
34+ * reader wants to access attributed text through the AttributedCharacterIterator
35+ * interface.
36+ *
37+ * <p>
38+ * An attribute is a key/value pair, identified by the key. No two
39+ * attributes on a given character can have the same key.
40+ *
41+ * <p>The values for an attribute are immutable, or must not be mutated
42+ * by clients or storage. They are always passed by reference, and not
43+ * cloned.
44+ *
45+ * @see AttributedCharacterIterator
46+ * @see Annotation
47+ * @since 1.2
48+ */
49+
50+public class AttributedString {
51+
52+ // since there are no vectors of int, we have to use arrays.
53+ // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
54+ private static final int ARRAY_SIZE_INCREMENT = 10;
55+
56+ // field holding the text
57+ String text;
58+
59+ // fields holding run attribute information
60+ // run attributes are organized by run
61+ int runArraySize; // current size of the arrays
62+ int runCount; // actual number of runs, <= runArraySize
63+ int runStarts[]; // start index for each run
64+ Vector runAttributes[]; // vector of attribute keys for each run
65+ Vector runAttributeValues[]; // parallel vector of attribute values for each run
66+
67+ /**
68+ * Constructs an AttributedString instance with the given
69+ * AttributedCharacterIterators.
70+ *
71+ * @param iterators AttributedCharacterIterators to construct
72+ * AttributedString from.
73+ * @throws NullPointerException if iterators is null
74+ */
75+ AttributedString(AttributedCharacterIterator[] iterators) {
76+ if (iterators == null) {
77+ throw new NullPointerException("Iterators must not be null");
78+ }
79+ if (iterators.length == 0) {
80+ text = "";
81+ }
82+ else {
83+ // Build the String contents
84+ StringBuffer buffer = new StringBuffer();
85+ for (int counter = 0; counter < iterators.length; counter++) {
86+ appendContents(buffer, iterators[counter]);
87+ }
88+
89+ text = buffer.toString();
90+
91+ if (text.length() > 0) {
92+ // Determine the runs, creating a new run when the attributes
93+ // differ.
94+ int offset = 0;
95+ Map last = null;
96+
97+ for (int counter = 0; counter < iterators.length; counter++) {
98+ AttributedCharacterIterator iterator = iterators[counter];
99+ int start = iterator.getBeginIndex();
100+ int end = iterator.getEndIndex();
101+ int index = start;
102+
103+ while (index < end) {
104+ iterator.setIndex(index);
105+
106+ Map attrs = iterator.getAttributes();
107+
108+ if (mapsDiffer(last, attrs)) {
109+ setAttributes(attrs, index - start + offset);
110+ }
111+ last = attrs;
112+ index = iterator.getRunLimit();
113+ }
114+ offset += (end - start);
115+ }
116+ }
117+ }
118+ }
119+
120+ /**
121+ * Constructs an AttributedString instance with the given text.
122+ * @param text The text for this attributed string.
123+ * @exception NullPointerException if <code>text</code> is null.
124+ */
125+ public AttributedString(String text) {
126+ if (text == null) {
127+ throw new NullPointerException();
128+ }
129+ this.text = text;
130+ }
131+
132+ /**
133+ * Constructs an AttributedString instance with the given text and attributes.
134+ * @param text The text for this attributed string.
135+ * @param attributes The attributes that apply to the entire string.
136+ * @exception NullPointerException if <code>text</code> or
137+ * <code>attributes</code> is null.
138+ * @exception IllegalArgumentException if the text has length 0
139+ * and the attributes parameter is not an empty Map (attributes
140+ * cannot be applied to a 0-length range).
141+ */
142+ public AttributedString(String text,
143+ Map<? extends Attribute, ?> attributes)
144+ {
145+ if (text == null || attributes == null) {
146+ throw new NullPointerException();
147+ }
148+ this.text = text;
149+
150+ if (text.length() == 0) {
151+ if (attributes.isEmpty())
152+ return;
153+ throw new IllegalArgumentException("Can't add attribute to 0-length text");
154+ }
155+
156+ int attributeCount = attributes.size();
157+ if (attributeCount > 0) {
158+ createRunAttributeDataVectors();
159+ Vector newRunAttributes = new Vector(attributeCount);
160+ Vector newRunAttributeValues = new Vector(attributeCount);
161+ runAttributes[0] = newRunAttributes;
162+ runAttributeValues[0] = newRunAttributeValues;
163+ Iterator iterator = attributes.entrySet().iterator();
164+ while (iterator.hasNext()) {
165+ Map.Entry entry = (Map.Entry) iterator.next();
166+ newRunAttributes.addElement(entry.getKey());
167+ newRunAttributeValues.addElement(entry.getValue());
168+ }
169+ }
170+ }
171+
172+ /**
173+ * Constructs an AttributedString instance with the given attributed
174+ * text represented by AttributedCharacterIterator.
175+ * @param text The text for this attributed string.
176+ * @exception NullPointerException if <code>text</code> is null.
177+ */
178+ public AttributedString(AttributedCharacterIterator text) {
179+ // If performance is critical, this constructor should be
180+ // implemented here rather than invoking the constructor for a
181+ // subrange. We can avoid some range checking in the loops.
182+ this(text, text.getBeginIndex(), text.getEndIndex(), null);
183+ }
184+
185+ /**
186+ * Constructs an AttributedString instance with the subrange of
187+ * the given attributed text represented by
188+ * AttributedCharacterIterator. If the given range produces an
189+ * empty text, all attributes will be discarded. Note that any
190+ * attributes wrapped by an Annotation object are discarded for a
191+ * subrange of the original attribute range.
192+ *
193+ * @param text The text for this attributed string.
194+ * @param beginIndex Index of the first character of the range.
195+ * @param endIndex Index of the character following the last character
196+ * of the range.
197+ * @exception NullPointerException if <code>text</code> is null.
198+ * @exception IllegalArgumentException if the subrange given by
199+ * beginIndex and endIndex is out of the text range.
200+ * @see java.text.Annotation
201+ */
202+ public AttributedString(AttributedCharacterIterator text,
203+ int beginIndex,
204+ int endIndex) {
205+ this(text, beginIndex, endIndex, null);
206+ }
207+
208+ /**
209+ * Constructs an AttributedString instance with the subrange of
210+ * the given attributed text represented by
211+ * AttributedCharacterIterator. Only attributes that match the
212+ * given attributes will be incorporated into the instance. If the
213+ * given range produces an empty text, all attributes will be
214+ * discarded. Note that any attributes wrapped by an Annotation
215+ * object are discarded for a subrange of the original attribute
216+ * range.
217+ *
218+ * @param text The text for this attributed string.
219+ * @param beginIndex Index of the first character of the range.
220+ * @param endIndex Index of the character following the last character
221+ * of the range.
222+ * @param attributes Specifies attributes to be extracted
223+ * from the text. If null is specified, all available attributes will
224+ * be used.
225+ * @exception NullPointerException if <code>text</code> is null.
226+ * @exception IllegalArgumentException if the subrange given by
227+ * beginIndex and endIndex is out of the text range.
228+ * @see java.text.Annotation
229+ */
230+ public AttributedString(AttributedCharacterIterator text,
231+ int beginIndex,
232+ int endIndex,
233+ Attribute[] attributes) {
234+ if (text == null) {
235+ throw new NullPointerException();
236+ }
237+
238+ // Validate the given subrange
239+ int textBeginIndex = text.getBeginIndex();
240+ int textEndIndex = text.getEndIndex();
241+ if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
242+ throw new IllegalArgumentException("Invalid substring range");
243+
244+ // Copy the given string
245+ StringBuffer textBuffer = new StringBuffer();
246+ text.setIndex(beginIndex);
247+ for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
248+ textBuffer.append(c);
249+ this.text = textBuffer.toString();
250+
251+ if (beginIndex == endIndex)
252+ return;
253+
254+ // Select attribute keys to be taken care of
255+ HashSet keys = new HashSet();
256+ if (attributes == null) {
257+ keys.addAll(text.getAllAttributeKeys());
258+ } else {
259+ for (int i = 0; i < attributes.length; i++)
260+ keys.add(attributes[i]);
261+ keys.retainAll(text.getAllAttributeKeys());
262+ }
263+ if (keys.isEmpty())
264+ return;
265+
266+ // Get and set attribute runs for each attribute name. Need to
267+ // scan from the top of the text so that we can discard any
268+ // Annotation that is no longer applied to a subset text segment.
269+ Iterator itr = keys.iterator();
270+ while (itr.hasNext()) {
271+ Attribute attributeKey = (Attribute)itr.next();
272+ text.setIndex(textBeginIndex);
273+ while (text.getIndex() < endIndex) {
274+ int start = text.getRunStart(attributeKey);
275+ int limit = text.getRunLimit(attributeKey);
276+ Object value = text.getAttribute(attributeKey);
277+
278+ if (value != null) {
279+ if (value instanceof Annotation) {
280+ if (start >= beginIndex && limit <= endIndex) {
281+ addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
282+ } else {
283+ if (limit > endIndex)
284+ break;
285+ }
286+ } else {
287+ // if the run is beyond the given (subset) range, we
288+ // don't need to process further.
289+ if (start >= endIndex)
290+ break;
291+ if (limit > beginIndex) {
292+ // attribute is applied to any subrange
293+ if (start < beginIndex)
294+ start = beginIndex;
295+ if (limit > endIndex)
296+ limit = endIndex;
297+ if (start != limit) {
298+ addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
299+ }
300+ }
301+ }
302+ }
303+ text.setIndex(limit);
304+ }
305+ }
306+ }
307+
308+ /**
309+ * Adds an attribute to the entire string.
310+ * @param attribute the attribute key
311+ * @param value the value of the attribute; may be null
312+ * @exception NullPointerException if <code>attribute</code> is null.
313+ * @exception IllegalArgumentException if the AttributedString has length 0
314+ * (attributes cannot be applied to a 0-length range).
315+ */
316+ public void addAttribute(Attribute attribute, Object value) {
317+
318+ if (attribute == null) {
319+ throw new NullPointerException();
320+ }
321+
322+ int len = length();
323+ if (len == 0) {
324+ throw new IllegalArgumentException("Can't add attribute to 0-length text");
325+ }
326+
327+ addAttributeImpl(attribute, value, 0, len);
328+ }
329+
330+ /**
331+ * Adds an attribute to a subrange of the string.
332+ * @param attribute the attribute key
333+ * @param value The value of the attribute. May be null.
334+ * @param beginIndex Index of the first character of the range.
335+ * @param endIndex Index of the character following the last character of the range.
336+ * @exception NullPointerException if <code>attribute</code> is null.
337+ * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
338+ * greater than the length of the string, or beginIndex and endIndex together don't
339+ * define a non-empty subrange of the string.
340+ */
341+ public void addAttribute(Attribute attribute, Object value,
342+ int beginIndex, int endIndex) {
343+
344+ if (attribute == null) {
345+ throw new NullPointerException();
346+ }
347+
348+ if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
349+ throw new IllegalArgumentException("Invalid substring range");
350+ }
351+
352+ addAttributeImpl(attribute, value, beginIndex, endIndex);
353+ }
354+
355+ /**
356+ * Adds a set of attributes to a subrange of the string.
357+ * @param attributes The attributes to be added to the string.
358+ * @param beginIndex Index of the first character of the range.
359+ * @param endIndex Index of the character following the last
360+ * character of the range.
361+ * @exception NullPointerException if <code>attributes</code> is null.
362+ * @exception IllegalArgumentException if beginIndex is less then
363+ * 0, endIndex is greater than the length of the string, or
364+ * beginIndex and endIndex together don't define a non-empty
365+ * subrange of the string and the attributes parameter is not an
366+ * empty Map.
367+ */
368+ public void addAttributes(Map<? extends Attribute, ?> attributes,
369+ int beginIndex, int endIndex)
370+ {
371+ if (attributes == null) {
372+ throw new NullPointerException();
373+ }
374+
375+ if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
376+ throw new IllegalArgumentException("Invalid substring range");
377+ }
378+ if (beginIndex == endIndex) {
379+ if (attributes.isEmpty())
380+ return;
381+ throw new IllegalArgumentException("Can't add attribute to 0-length text");
382+ }
383+
384+ // make sure we have run attribute data vectors
385+ if (runCount == 0) {
386+ createRunAttributeDataVectors();
387+ }
388+
389+ // break up runs if necessary
390+ int beginRunIndex = ensureRunBreak(beginIndex);
391+ int endRunIndex = ensureRunBreak(endIndex);
392+
393+ Iterator iterator = attributes.entrySet().iterator();
394+ while (iterator.hasNext()) {
395+ Map.Entry entry = (Map.Entry) iterator.next();
396+ addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
397+ }
398+ }
399+
400+ private synchronized void addAttributeImpl(Attribute attribute, Object value,
401+ int beginIndex, int endIndex) {
402+
403+ // make sure we have run attribute data vectors
404+ if (runCount == 0) {
405+ createRunAttributeDataVectors();
406+ }
407+
408+ // break up runs if necessary
409+ int beginRunIndex = ensureRunBreak(beginIndex);
410+ int endRunIndex = ensureRunBreak(endIndex);
411+
412+ addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
413+ }
414+
415+ private final void createRunAttributeDataVectors() {
416+ // use temporary variables so things remain consistent in case of an exception
417+ int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
418+ Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT];
419+ Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT];
420+ runStarts = newRunStarts;
421+ runAttributes = newRunAttributes;
422+ runAttributeValues = newRunAttributeValues;
423+ runArraySize = ARRAY_SIZE_INCREMENT;
424+ runCount = 1; // assume initial run starting at index 0
425+ }
426+
427+ // ensure there's a run break at offset, return the index of the run
428+ private final int ensureRunBreak(int offset) {
429+ return ensureRunBreak(offset, true);
430+ }
431+
432+ /**
433+ * Ensures there is a run break at offset, returning the index of
434+ * the run. If this results in splitting a run, two things can happen:
435+ * <ul>
436+ * <li>If copyAttrs is true, the attributes from the existing run
437+ * will be placed in both of the newly created runs.
438+ * <li>If copyAttrs is false, the attributes from the existing run
439+ * will NOT be copied to the run to the right (>= offset) of the break,
440+ * but will exist on the run to the left (< offset).
441+ * </ul>
442+ */
443+ private final int ensureRunBreak(int offset, boolean copyAttrs) {
444+ if (offset == length()) {
445+ return runCount;
446+ }
447+
448+ // search for the run index where this offset should be
449+ int runIndex = 0;
450+ while (runIndex < runCount && runStarts[runIndex] < offset) {
451+ runIndex++;
452+ }
453+
454+ // if the offset is at a run start already, we're done
455+ if (runIndex < runCount && runStarts[runIndex] == offset) {
456+ return runIndex;
457+ }
458+
459+ // we'll have to break up a run
460+ // first, make sure we have enough space in our arrays
461+ if (runCount == runArraySize) {
462+ int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
463+ int newRunStarts[] = new int[newArraySize];
464+ Vector newRunAttributes[] = new Vector[newArraySize];
465+ Vector newRunAttributeValues[] = new Vector[newArraySize];
466+ for (int i = 0; i < runArraySize; i++) {
467+ newRunStarts[i] = runStarts[i];
468+ newRunAttributes[i] = runAttributes[i];
469+ newRunAttributeValues[i] = runAttributeValues[i];
470+ }
471+ runStarts = newRunStarts;
472+ runAttributes = newRunAttributes;
473+ runAttributeValues = newRunAttributeValues;
474+ runArraySize = newArraySize;
475+ }
476+
477+ // make copies of the attribute information of the old run that the new one used to be part of
478+ // use temporary variables so things remain consistent in case of an exception
479+ Vector newRunAttributes = null;
480+ Vector newRunAttributeValues = null;
481+
482+ if (copyAttrs) {
483+ Vector oldRunAttributes = runAttributes[runIndex - 1];
484+ Vector oldRunAttributeValues = runAttributeValues[runIndex - 1];
485+ if (oldRunAttributes != null) {
486+ newRunAttributes = (Vector) oldRunAttributes.clone();
487+ }
488+ if (oldRunAttributeValues != null) {
489+ newRunAttributeValues = (Vector) oldRunAttributeValues.clone();
490+ }
491+ }
492+
493+ // now actually break up the run
494+ runCount++;
495+ for (int i = runCount - 1; i > runIndex; i--) {
496+ runStarts[i] = runStarts[i - 1];
497+ runAttributes[i] = runAttributes[i - 1];
498+ runAttributeValues[i] = runAttributeValues[i - 1];
499+ }
500+ runStarts[runIndex] = offset;
501+ runAttributes[runIndex] = newRunAttributes;
502+ runAttributeValues[runIndex] = newRunAttributeValues;
503+
504+ return runIndex;
505+ }
506+
507+ // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
508+ private void addAttributeRunData(Attribute attribute, Object value,
509+ int beginRunIndex, int endRunIndex) {
510+
511+ for (int i = beginRunIndex; i < endRunIndex; i++) {
512+ int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
513+ if (runAttributes[i] == null) {
514+ Vector newRunAttributes = new Vector();
515+ Vector newRunAttributeValues = new Vector();
516+ runAttributes[i] = newRunAttributes;
517+ runAttributeValues[i] = newRunAttributeValues;
518+ } else {
519+ // check whether we have an entry already
520+ keyValueIndex = runAttributes[i].indexOf(attribute);
521+ }
522+
523+ if (keyValueIndex == -1) {
524+ // create new entry
525+ int oldSize = runAttributes[i].size();
526+ runAttributes[i].addElement(attribute);
527+ try {
528+ runAttributeValues[i].addElement(value);
529+ }
530+ catch (Exception e) {
531+ runAttributes[i].setSize(oldSize);
532+ runAttributeValues[i].setSize(oldSize);
533+ }
534+ } else {
535+ // update existing entry
536+ runAttributeValues[i].set(keyValueIndex, value);
537+ }
538+ }
539+ }
540+
541+ /**
542+ * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
543+ * this string.
544+ *
545+ * @return An iterator providing access to the text and its attributes.
546+ */
547+ public AttributedCharacterIterator getIterator() {
548+ return getIterator(null, 0, length());
549+ }
550+
551+ /**
552+ * Creates an AttributedCharacterIterator instance that provides access to
553+ * selected contents of this string.
554+ * Information about attributes not listed in attributes that the
555+ * implementor may have need not be made accessible through the iterator.
556+ * If the list is null, all available attribute information should be made
557+ * accessible.
558+ *
559+ * @param attributes a list of attributes that the client is interested in
560+ * @return an iterator providing access to the entire text and its selected attributes
561+ */
562+ public AttributedCharacterIterator getIterator(Attribute[] attributes) {
563+ return getIterator(attributes, 0, length());
564+ }
565+
566+ /**
567+ * Creates an AttributedCharacterIterator instance that provides access to
568+ * selected contents of this string.
569+ * Information about attributes not listed in attributes that the
570+ * implementor may have need not be made accessible through the iterator.
571+ * If the list is null, all available attribute information should be made
572+ * accessible.
573+ *
574+ * @param attributes a list of attributes that the client is interested in
575+ * @param beginIndex the index of the first character
576+ * @param endIndex the index of the character following the last character
577+ * @return an iterator providing access to the text and its attributes
578+ * @exception IllegalArgumentException if beginIndex is less then 0,
579+ * endIndex is greater than the length of the string, or beginIndex is
580+ * greater than endIndex.
581+ */
582+ public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
583+ return new AttributedStringIterator(attributes, beginIndex, endIndex);
584+ }
585+
586+ // all (with the exception of length) reading operations are private,
587+ // since AttributedString instances are accessed through iterators.
588+
589+ // length is package private so that CharacterIteratorFieldDelegate can
590+ // access it without creating an AttributedCharacterIterator.
591+ int length() {
592+ return text.length();
593+ }
594+
595+ private char charAt(int index) {
596+ return text.charAt(index);
597+ }
598+
599+ private synchronized Object getAttribute(Attribute attribute, int runIndex) {
600+ Vector currentRunAttributes = runAttributes[runIndex];
601+ Vector currentRunAttributeValues = runAttributeValues[runIndex];
602+ if (currentRunAttributes == null) {
603+ return null;
604+ }
605+ int attributeIndex = currentRunAttributes.indexOf(attribute);
606+ if (attributeIndex != -1) {
607+ return currentRunAttributeValues.elementAt(attributeIndex);
608+ }
609+ else {
610+ return null;
611+ }
612+ }
613+
614+ // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
615+ private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
616+ Object value = getAttribute(attribute, runIndex);
617+ if (value instanceof Annotation) {
618+ // need to check whether the annotation's range extends outside the iterator's range
619+ if (beginIndex > 0) {
620+ int currIndex = runIndex;
621+ int runStart = runStarts[currIndex];
622+ while (runStart >= beginIndex &&
623+ valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
624+ currIndex--;
625+ runStart = runStarts[currIndex];
626+ }
627+ if (runStart < beginIndex) {
628+ // annotation's range starts before iterator's range
629+ return null;
630+ }
631+ }
632+ int textLength = length();
633+ if (endIndex < textLength) {
634+ int currIndex = runIndex;
635+ int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
636+ while (runLimit <= endIndex &&
637+ valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
638+ currIndex++;
639+ runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
640+ }
641+ if (runLimit > endIndex) {
642+ // annotation's range ends after iterator's range
643+ return null;
644+ }
645+ }
646+ // annotation's range is subrange of iterator's range,
647+ // so we can return the value
648+ }
649+ return value;
650+ }
651+
652+ // returns whether all specified attributes have equal values in the runs with the given indices
653+ private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) {
654+ Iterator iterator = attributes.iterator();
655+ while (iterator.hasNext()) {
656+ Attribute key = (Attribute) iterator.next();
657+ if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
658+ return false;
659+ }
660+ }
661+ return true;
662+ }
663+
664+ // returns whether the two objects are either both null or equal
665+ private final static boolean valuesMatch(Object value1, Object value2) {
666+ if (value1 == null) {
667+ return value2 == null;
668+ } else {
669+ return value1.equals(value2);
670+ }
671+ }
672+
673+ /**
674+ * Appends the contents of the CharacterIterator iterator into the
675+ * StringBuffer buf.
676+ */
677+ private final void appendContents(StringBuffer buf,
678+ CharacterIterator iterator) {
679+ int index = iterator.getBeginIndex();
680+ int end = iterator.getEndIndex();
681+
682+ while (index < end) {
683+ iterator.setIndex(index++);
684+ buf.append(iterator.current());
685+ }
686+ }
687+
688+ /**
689+ * Sets the attributes for the range from offset to the next run break
690+ * (typically the end of the text) to the ones specified in attrs.
691+ * This is only meant to be called from the constructor!
692+ */
693+ private void setAttributes(Map attrs, int offset) {
694+ if (runCount == 0) {
695+ createRunAttributeDataVectors();
696+ }
697+
698+ int index = ensureRunBreak(offset, false);
699+ int size;
700+
701+ if (attrs != null && (size = attrs.size()) > 0) {
702+ Vector runAttrs = new Vector(size);
703+ Vector runValues = new Vector(size);
704+ Iterator iterator = attrs.entrySet().iterator();
705+
706+ while (iterator.hasNext()) {
707+ Map.Entry entry = (Map.Entry)iterator.next();
708+
709+ runAttrs.add(entry.getKey());
710+ runValues.add(entry.getValue());
711+ }
712+ runAttributes[index] = runAttrs;
713+ runAttributeValues[index] = runValues;
714+ }
715+ }
716+
717+ /**
718+ * Returns true if the attributes specified in last and attrs differ.
719+ */
720+ private static boolean mapsDiffer(Map last, Map attrs) {
721+ if (last == null) {
722+ return (attrs != null && attrs.size() > 0);
723+ }
724+ return (!last.equals(attrs));
725+ }
726+
727+
728+ // the iterator class associated with this string class
729+
730+ final private class AttributedStringIterator implements AttributedCharacterIterator {
731+
732+ // note on synchronization:
733+ // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
734+ // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
735+
736+ // start and end index for our iteration
737+ private int beginIndex;
738+ private int endIndex;
739+
740+ // attributes that our client is interested in
741+ private Attribute[] relevantAttributes;
742+
743+ // the current index for our iteration
744+ // invariant: beginIndex <= currentIndex <= endIndex
745+ private int currentIndex;
746+
747+ // information about the run that includes currentIndex
748+ private int currentRunIndex;
749+ private int currentRunStart;
750+ private int currentRunLimit;
751+
752+ // constructor
753+ AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
754+
755+ if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
756+ throw new IllegalArgumentException("Invalid substring range");
757+ }
758+
759+ this.beginIndex = beginIndex;
760+ this.endIndex = endIndex;
761+ this.currentIndex = beginIndex;
762+ updateRunInfo();
763+ if (attributes != null) {
764+ relevantAttributes = (Attribute[]) attributes.clone();
765+ }
766+ }
767+
768+ // Object methods. See documentation in that class.
769+
770+ public boolean equals(Object obj) {
771+ if (this == obj) {
772+ return true;
773+ }
774+ if (!(obj instanceof AttributedStringIterator)) {
775+ return false;
776+ }
777+
778+ AttributedStringIterator that = (AttributedStringIterator) obj;
779+
780+ if (AttributedString.this != that.getString())
781+ return false;
782+ if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
783+ return false;
784+ return true;
785+ }
786+
787+ public int hashCode() {
788+ return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
789+ }
790+
791+ public Object clone() {
792+ try {
793+ AttributedStringIterator other = (AttributedStringIterator) super.clone();
794+ return other;
795+ }
796+ catch (CloneNotSupportedException e) {
797+ throw new InternalError();
798+ }
799+ }
800+
801+ // CharacterIterator methods. See documentation in that interface.
802+
803+ public char first() {
804+ return internalSetIndex(beginIndex);
805+ }
806+
807+ public char last() {
808+ if (endIndex == beginIndex) {
809+ return internalSetIndex(endIndex);
810+ } else {
811+ return internalSetIndex(endIndex - 1);
812+ }
813+ }
814+
815+ public char current() {
816+ if (currentIndex == endIndex) {
817+ return DONE;
818+ } else {
819+ return charAt(currentIndex);
820+ }
821+ }
822+
823+ public char next() {
824+ if (currentIndex < endIndex) {
825+ return internalSetIndex(currentIndex + 1);
826+ }
827+ else {
828+ return DONE;
829+ }
830+ }
831+
832+ public char previous() {
833+ if (currentIndex > beginIndex) {
834+ return internalSetIndex(currentIndex - 1);
835+ }
836+ else {
837+ return DONE;
838+ }
839+ }
840+
841+ public char setIndex(int position) {
842+ if (position < beginIndex || position > endIndex)
843+ throw new IllegalArgumentException("Invalid index");
844+ return internalSetIndex(position);
845+ }
846+
847+ public int getBeginIndex() {
848+ return beginIndex;
849+ }
850+
851+ public int getEndIndex() {
852+ return endIndex;
853+ }
854+
855+ public int getIndex() {
856+ return currentIndex;
857+ }
858+
859+ // AttributedCharacterIterator methods. See documentation in that interface.
860+
861+ public int getRunStart() {
862+ return currentRunStart;
863+ }
864+
865+ public int getRunStart(Attribute attribute) {
866+ if (currentRunStart == beginIndex || currentRunIndex == -1) {
867+ return currentRunStart;
868+ } else {
869+ Object value = getAttribute(attribute);
870+ int runStart = currentRunStart;
871+ int runIndex = currentRunIndex;
872+ while (runStart > beginIndex &&
873+ valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
874+ runIndex--;
875+ runStart = runStarts[runIndex];
876+ }
877+ if (runStart < beginIndex) {
878+ runStart = beginIndex;
879+ }
880+ return runStart;
881+ }
882+ }
883+
884+ public int getRunStart(Set<? extends Attribute> attributes) {
885+ if (currentRunStart == beginIndex || currentRunIndex == -1) {
886+ return currentRunStart;
887+ } else {
888+ int runStart = currentRunStart;
889+ int runIndex = currentRunIndex;
890+ while (runStart > beginIndex &&
891+ AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
892+ runIndex--;
893+ runStart = runStarts[runIndex];
894+ }
895+ if (runStart < beginIndex) {
896+ runStart = beginIndex;
897+ }
898+ return runStart;
899+ }
900+ }
901+
902+ public int getRunLimit() {
903+ return currentRunLimit;
904+ }
905+
906+ public int getRunLimit(Attribute attribute) {
907+ if (currentRunLimit == endIndex || currentRunIndex == -1) {
908+ return currentRunLimit;
909+ } else {
910+ Object value = getAttribute(attribute);
911+ int runLimit = currentRunLimit;
912+ int runIndex = currentRunIndex;
913+ while (runLimit < endIndex &&
914+ valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
915+ runIndex++;
916+ runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
917+ }
918+ if (runLimit > endIndex) {
919+ runLimit = endIndex;
920+ }
921+ return runLimit;
922+ }
923+ }
924+
925+ public int getRunLimit(Set<? extends Attribute> attributes) {
926+ if (currentRunLimit == endIndex || currentRunIndex == -1) {
927+ return currentRunLimit;
928+ } else {
929+ int runLimit = currentRunLimit;
930+ int runIndex = currentRunIndex;
931+ while (runLimit < endIndex &&
932+ AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
933+ runIndex++;
934+ runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
935+ }
936+ if (runLimit > endIndex) {
937+ runLimit = endIndex;
938+ }
939+ return runLimit;
940+ }
941+ }
942+
943+ public Map<Attribute,Object> getAttributes() {
944+ if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
945+ // ??? would be nice to return null, but current spec doesn't allow it
946+ // returning Hashtable saves AttributeMap from dealing with emptiness
947+ return new Hashtable();
948+ }
949+ return new AttributeMap(currentRunIndex, beginIndex, endIndex);
950+ }
951+
952+ public Set<Attribute> getAllAttributeKeys() {
953+ // ??? This should screen out attribute keys that aren't relevant to the client
954+ if (runAttributes == null) {
955+ // ??? would be nice to return null, but current spec doesn't allow it
956+ // returning HashSet saves us from dealing with emptiness
957+ return new HashSet();
958+ }
959+ synchronized (AttributedString.this) {
960+ // ??? should try to create this only once, then update if necessary,
961+ // and give callers read-only view
962+ Set keys = new HashSet();
963+ int i = 0;
964+ while (i < runCount) {
965+ if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
966+ Vector currentRunAttributes = runAttributes[i];
967+ if (currentRunAttributes != null) {
968+ int j = currentRunAttributes.size();
969+ while (j-- > 0) {
970+ keys.add(currentRunAttributes.get(j));
971+ }
972+ }
973+ }
974+ i++;
975+ }
976+ return keys;
977+ }
978+ }
979+
980+ public Object getAttribute(Attribute attribute) {
981+ int runIndex = currentRunIndex;
982+ if (runIndex < 0) {
983+ return null;
984+ }
985+ return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
986+ }
987+
988+ // internally used methods
989+
990+ private AttributedString getString() {
991+ return AttributedString.this;
992+ }
993+
994+ // set the current index, update information about the current run if necessary,
995+ // return the character at the current index
996+ private char internalSetIndex(int position) {
997+ currentIndex = position;
998+ if (position < currentRunStart || position >= currentRunLimit) {
999+ updateRunInfo();
1000+ }
1001+ if (currentIndex == endIndex) {
1002+ return DONE;
1003+ } else {
1004+ return charAt(position);
1005+ }
1006+ }
1007+
1008+ // update the information about the current run
1009+ private void updateRunInfo() {
1010+ if (currentIndex == endIndex) {
1011+ currentRunStart = currentRunLimit = endIndex;
1012+ currentRunIndex = -1;
1013+ } else {
1014+ synchronized (AttributedString.this) {
1015+ int runIndex = -1;
1016+ while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
1017+ runIndex++;
1018+ currentRunIndex = runIndex;
1019+ if (runIndex >= 0) {
1020+ currentRunStart = runStarts[runIndex];
1021+ if (currentRunStart < beginIndex)
1022+ currentRunStart = beginIndex;
1023+ }
1024+ else {
1025+ currentRunStart = beginIndex;
1026+ }
1027+ if (runIndex < runCount - 1) {
1028+ currentRunLimit = runStarts[runIndex + 1];
1029+ if (currentRunLimit > endIndex)
1030+ currentRunLimit = endIndex;
1031+ }
1032+ else {
1033+ currentRunLimit = endIndex;
1034+ }
1035+ }
1036+ }
1037+ }
1038+
1039+ }
1040+
1041+ // the map class associated with this string class, giving access to the attributes of one run
1042+
1043+ final private class AttributeMap extends AbstractMap<Attribute,Object> {
1044+
1045+ int runIndex;
1046+ int beginIndex;
1047+ int endIndex;
1048+
1049+ AttributeMap(int runIndex, int beginIndex, int endIndex) {
1050+ this.runIndex = runIndex;
1051+ this.beginIndex = beginIndex;
1052+ this.endIndex = endIndex;
1053+ }
1054+
1055+ public Set entrySet() {
1056+ HashSet set = new HashSet();
1057+ synchronized (AttributedString.this) {
1058+ int size = runAttributes[runIndex].size();
1059+ for (int i = 0; i < size; i++) {
1060+ Attribute key = (Attribute) runAttributes[runIndex].get(i);
1061+ Object value = runAttributeValues[runIndex].get(i);
1062+ if (value instanceof Annotation) {
1063+ value = AttributedString.this.getAttributeCheckRange(key,
1064+ runIndex, beginIndex, endIndex);
1065+ if (value == null) {
1066+ continue;
1067+ }
1068+ }
1069+ Map.Entry entry = new AttributeEntry(key, value);
1070+ set.add(entry);
1071+ }
1072+ }
1073+ return set;
1074+ }
1075+
1076+ public Object get(Object key) {
1077+ return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
1078+ }
1079+ }
1080+}
1081+
1082+class AttributeEntry implements Map.Entry {
1083+
1084+ private Attribute key;
1085+ private Object value;
1086+
1087+ AttributeEntry(Attribute key, Object value) {
1088+ this.key = key;
1089+ this.value = value;
1090+ }
1091+
1092+ public boolean equals(Object o) {
1093+ if (!(o instanceof AttributeEntry)) {
1094+ return false;
1095+ }
1096+ AttributeEntry other = (AttributeEntry) o;
1097+ return other.key.equals(key) &&
1098+ (value == null ? other.value == null : other.value.equals(value));
1099+ }
1100+
1101+ public Object getKey() {
1102+ return key;
1103+ }
1104+
1105+ public Object getValue() {
1106+ return value;
1107+ }
1108+
1109+ public Object setValue(Object newValue) {
1110+ throw new UnsupportedOperationException();
1111+ }
1112+
1113+ public int hashCode() {
1114+ return key.hashCode() ^ (value==null ? 0 : value.hashCode());
1115+ }
1116+
1117+ public String toString() {
1118+ return key.toString()+"="+value.toString();
1119+ }
1120+}
java/pkg/java/text/Bidi.class+0−0

Binary file not shown.

java/pkg/java/text/Bidi.java+328−0
@@ -0,0 +1,328 @@
1+/*
2+ * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright IBM Corp. 1999-2003 - All Rights Reserved
28+ *
29+ * The original version of this source code and documentation is
30+ * copyrighted and owned by IBM. These materials are provided
31+ * under terms of a License Agreement between IBM and Sun.
32+ * This technology is protected by multiple US and International
33+ * patents. This notice and attribution to IBM may not be removed.
34+ */
35+
36+package java.text;
37+
38+import sun.text.bidi.BidiBase;
39+
40+/**
41+ * This class implements the Unicode Bidirectional Algorithm.
42+ * <p>
43+ * A Bidi object provides information on the bidirectional reordering of the text
44+ * used to create it. This is required, for example, to properly display Arabic
45+ * or Hebrew text. These languages are inherently mixed directional, as they order
46+ * numbers from left-to-right while ordering most other text from right-to-left.
47+ * <p>
48+ * Once created, a Bidi object can be queried to see if the text it represents is
49+ * all left-to-right or all right-to-left. Such objects are very lightweight and
50+ * this text is relatively easy to process.
51+ * <p>
52+ * If there are multiple runs of text, information about the runs can be accessed
53+ * by indexing to get the start, limit, and level of a run. The level represents
54+ * both the direction and the 'nesting level' of a directional run. Odd levels
55+ * are right-to-left, while even levels are left-to-right. So for example level
56+ * 0 represents left-to-right text, while level 1 represents right-to-left text, and
57+ * level 2 represents left-to-right text embedded in a right-to-left run.
58+ *
59+ * @since 1.4
60+ */
61+public final class Bidi {
62+
63+ /** Constant indicating base direction is left-to-right. */
64+ public static final int DIRECTION_LEFT_TO_RIGHT = 0;
65+
66+ /** Constant indicating base direction is right-to-left. */
67+ public static final int DIRECTION_RIGHT_TO_LEFT = 1;
68+
69+ /**
70+ * Constant indicating that the base direction depends on the first strong
71+ * directional character in the text according to the Unicode
72+ * Bidirectional Algorithm. If no strong directional character is present,
73+ * the base direction is left-to-right.
74+ */
75+ public static final int DIRECTION_DEFAULT_LEFT_TO_RIGHT = -2;
76+
77+ /**
78+ * Constant indicating that the base direction depends on the first strong
79+ * directional character in the text according to the Unicode
80+ * Bidirectional Algorithm. If no strong directional character is present,
81+ * the base direction is right-to-left.
82+ */
83+ public static final int DIRECTION_DEFAULT_RIGHT_TO_LEFT = -1;
84+
85+ private BidiBase bidiBase;
86+
87+ /**
88+ * Create Bidi from the given paragraph of text and base direction.
89+ * @param paragraph a paragraph of text
90+ * @param flags a collection of flags that control the algorithm. The
91+ * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
92+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
93+ * Other values are reserved.
94+ */
95+ public Bidi(String paragraph, int flags) {
96+ if (paragraph == null) {
97+ throw new IllegalArgumentException("paragraph is null");
98+ }
99+
100+ bidiBase = new BidiBase(paragraph.toCharArray(), 0, null, 0, paragraph.length(), flags);
101+ }
102+
103+ /**
104+ * Create Bidi from the given paragraph of text.
105+ * <p>
106+ * The RUN_DIRECTION attribute in the text, if present, determines the base
107+ * direction (left-to-right or right-to-left). If not present, the base
108+ * direction is computes using the Unicode Bidirectional Algorithm, defaulting to left-to-right
109+ * if there are no strong directional characters in the text. This attribute, if
110+ * present, must be applied to all the text in the paragraph.
111+ * <p>
112+ * The BIDI_EMBEDDING attribute in the text, if present, represents embedding level
113+ * information. Negative values from -1 to -62 indicate overrides at the absolute value
114+ * of the level. Positive values from 1 to 62 indicate embeddings. Where values are
115+ * zero or not defined, the base embedding level as determined by the base direction
116+ * is assumed.
117+ * <p>
118+ * The NUMERIC_SHAPING attribute in the text, if present, converts European digits to
119+ * other decimal digits before running the bidi algorithm. This attribute, if present,
120+ * must be applied to all the text in the paragraph.
121+ *
122+ * @param paragraph a paragraph of text with optional character and paragraph attribute information
123+ *
124+ * @see java.awt.font.TextAttribute#BIDI_EMBEDDING
125+ * @see java.awt.font.TextAttribute#NUMERIC_SHAPING
126+ * @see java.awt.font.TextAttribute#RUN_DIRECTION
127+ */
128+ public Bidi(AttributedCharacterIterator paragraph) {
129+ if (paragraph == null) {
130+ throw new IllegalArgumentException("paragraph is null");
131+ }
132+
133+ bidiBase = new BidiBase(0, 0);
134+ bidiBase.setPara(paragraph);
135+ }
136+
137+ /**
138+ * Create Bidi from the given text, embedding, and direction information.
139+ * The embeddings array may be null. If present, the values represent embedding level
140+ * information. Negative values from -1 to -61 indicate overrides at the absolute value
141+ * of the level. Positive values from 1 to 61 indicate embeddings. Where values are
142+ * zero, the base embedding level as determined by the base direction is assumed.
143+ * @param text an array containing the paragraph of text to process.
144+ * @param textStart the index into the text array of the start of the paragraph.
145+ * @param embeddings an array containing embedding values for each character in the paragraph.
146+ * This can be null, in which case it is assumed that there is no external embedding information.
147+ * @param embStart the index into the embedding array of the start of the paragraph.
148+ * @param paragraphLength the length of the paragraph in the text and embeddings arrays.
149+ * @param flags a collection of flags that control the algorithm. The
150+ * algorithm understands the flags DIRECTION_LEFT_TO_RIGHT, DIRECTION_RIGHT_TO_LEFT,
151+ * DIRECTION_DEFAULT_LEFT_TO_RIGHT, and DIRECTION_DEFAULT_RIGHT_TO_LEFT.
152+ * Other values are reserved.
153+ */
154+ public Bidi(char[] text, int textStart, byte[] embeddings, int embStart, int paragraphLength, int flags) {
155+ if (text == null) {
156+ throw new IllegalArgumentException("text is null");
157+ }
158+ if (paragraphLength < 0) {
159+ throw new IllegalArgumentException("bad length: " + paragraphLength);
160+ }
161+ if (textStart < 0 || paragraphLength > text.length - textStart) {
162+ throw new IllegalArgumentException("bad range: " + textStart +
163+ " length: " + paragraphLength +
164+ " for text of length: " + text.length);
165+ }
166+ if (embeddings != null && (embStart < 0 || paragraphLength > embeddings.length - embStart)) {
167+ throw new IllegalArgumentException("bad range: " + embStart +
168+ " length: " + paragraphLength +
169+ " for embeddings of length: " + text.length);
170+ }
171+
172+ bidiBase = new BidiBase(text, textStart, embeddings, embStart, paragraphLength, flags);
173+ }
174+
175+ /**
176+ * Create a Bidi object representing the bidi information on a line of text within
177+ * the paragraph represented by the current Bidi. This call is not required if the
178+ * entire paragraph fits on one line.
179+ * @param lineStart the offset from the start of the paragraph to the start of the line.
180+ * @param lineLimit the offset from the start of the paragraph to the limit of the line.
181+ */
182+ public Bidi createLineBidi(int lineStart, int lineLimit) {
183+ AttributedString astr = new AttributedString("");
184+ Bidi newBidi = new Bidi(astr.getIterator());
185+
186+ return bidiBase.setLine(this, bidiBase, newBidi, newBidi.bidiBase,lineStart, lineLimit);
187+ }
188+
189+ /**
190+ * Return true if the line is not left-to-right or right-to-left. This means it either has mixed runs of left-to-right
191+ * and right-to-left text, or the base direction differs from the direction of the only run of text.
192+ * @return true if the line is not left-to-right or right-to-left.
193+ */
194+ public boolean isMixed() {
195+ return bidiBase.isMixed();
196+ }
197+
198+ /**
199+ * Return true if the line is all left-to-right text and the base direction is left-to-right.
200+ * @return true if the line is all left-to-right text and the base direction is left-to-right
201+ */
202+ public boolean isLeftToRight() {
203+ return bidiBase.isLeftToRight();
204+ }
205+
206+ /**
207+ * Return true if the line is all right-to-left text, and the base direction is right-to-left.
208+ * @return true if the line is all right-to-left text, and the base direction is right-to-left
209+ */
210+ public boolean isRightToLeft() {
211+ return bidiBase.isRightToLeft();
212+ }
213+
214+ /**
215+ * Return the length of text in the line.
216+ * @return the length of text in the line
217+ */
218+ public int getLength() {
219+ return bidiBase.getLength();
220+ }
221+
222+ /**
223+ * Return true if the base direction is left-to-right.
224+ * @return true if the base direction is left-to-right
225+ */
226+ public boolean baseIsLeftToRight() {
227+ return bidiBase.baseIsLeftToRight();
228+ }
229+
230+ /**
231+ * Return the base level (0 if left-to-right, 1 if right-to-left).
232+ * @return the base level
233+ */
234+ public int getBaseLevel() {
235+ return bidiBase.getParaLevel();
236+ }
237+
238+ /**
239+ * Return the resolved level of the character at offset. If offset is <0 or >=
240+ * the length of the line, return the base direction level.
241+ * @param offset the index of the character for which to return the level
242+ * @return the resolved level of the character at offset
243+ */
244+ public int getLevelAt(int offset) {
245+ return bidiBase.getLevelAt(offset);
246+ }
247+
248+ /**
249+ * Return the number of level runs.
250+ * @return the number of level runs
251+ */
252+ public int getRunCount() {
253+ return bidiBase.countRuns();
254+ }
255+
256+ /**
257+ * Return the level of the nth logical run in this line.
258+ * @param run the index of the run, between 0 and <code>getRunCount()</code>
259+ * @return the level of the run
260+ */
261+ public int getRunLevel(int run) {
262+ return bidiBase.getRunLevel(run);
263+ }
264+
265+ /**
266+ * Return the index of the character at the start of the nth logical run in this line, as
267+ * an offset from the start of the line.
268+ * @param run the index of the run, between 0 and <code>getRunCount()</code>
269+ * @return the start of the run
270+ */
271+ public int getRunStart(int run) {
272+ return bidiBase.getRunStart(run);
273+ }
274+
275+ /**
276+ * Return the index of the character past the end of the nth logical run in this line, as
277+ * an offset from the start of the line. For example, this will return the length
278+ * of the line for the last run on the line.
279+ * @param run the index of the run, between 0 and <code>getRunCount()</code>
280+ * @return limit the limit of the run
281+ */
282+ public int getRunLimit(int run) {
283+ return bidiBase.getRunLimit(run);
284+ }
285+
286+ /**
287+ * Return true if the specified text requires bidi analysis. If this returns false,
288+ * the text will display left-to-right. Clients can then avoid constructing a Bidi object.
289+ * Text in the Arabic Presentation Forms area of Unicode is presumed to already be shaped
290+ * and ordered for display, and so will not cause this function to return true.
291+ *
292+ * @param text the text containing the characters to test
293+ * @param start the start of the range of characters to test
294+ * @param limit the limit of the range of characters to test
295+ * @return true if the range of characters requires bidi analysis
296+ */
297+ public static boolean requiresBidi(char[] text, int start, int limit) {
298+ return BidiBase.requiresBidi(text, start, limit);
299+ }
300+
301+ /**
302+ * Reorder the objects in the array into visual order based on their levels.
303+ * This is a utility function to use when you have a collection of objects
304+ * representing runs of text in logical order, each run containing text
305+ * at a single level. The elements at <code>index</code> from
306+ * <code>objectStart</code> up to <code>objectStart + count</code>
307+ * in the objects array will be reordered into visual order assuming
308+ * each run of text has the level indicated by the corresponding element
309+ * in the levels array (at <code>index - objectStart + levelStart</code>).
310+ *
311+ * @param levels an array representing the bidi level of each object
312+ * @param levelStart the start position in the levels array
313+ * @param objects the array of objects to be reordered into visual order
314+ * @param objectStart the start position in the objects array
315+ * @param count the number of objects to reorder
316+ */
317+ public static void reorderVisually(byte[] levels, int levelStart, Object[] objects, int objectStart, int count) {
318+ BidiBase.reorderVisually(levels, levelStart, objects, objectStart, count);
319+ }
320+
321+ /**
322+ * Display the bidi internal state, used in debugging.
323+ */
324+ public String toString() {
325+ return bidiBase.toString();
326+ }
327+
328+}
java/pkg/java/text/BreakDictionary$1.class+0−0

Binary file not shown.

java/pkg/java/text/BreakDictionary.class+0−0

Binary file not shown.

java/pkg/java/text/BreakDictionary.java+341−0
@@ -0,0 +1,341 @@
1+/*
2+ * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ *
28+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
29+ * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved
30+ *
31+ * The original version of this source code and documentation
32+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
33+ * subsidiary of IBM. These materials are provided under terms
34+ * of a License Agreement between Taligent and Sun. This technology
35+ * is protected by multiple US and International patents.
36+ *
37+ * This notice and attribution to Taligent may not be removed.
38+ * Taligent is a registered trademark of Taligent, Inc.
39+ */
40+package java.text;
41+
42+import java.io.*;
43+import java.security.AccessController;
44+import java.security.PrivilegedActionException;
45+import java.security.PrivilegedExceptionAction;
46+import java.util.MissingResourceException;
47+import sun.text.CompactByteArray;
48+import sun.text.SupplementaryCharacterData;
49+
50+/**
51+ * This is the class that represents the list of known words used by
52+ * DictionaryBasedBreakIterator. The conceptual data structure used
53+ * here is a trie: there is a node hanging off the root node for every
54+ * letter that can start a word. Each of these nodes has a node hanging
55+ * off of it for every letter that can be the second letter of a word
56+ * if this node is the first letter, and so on. The trie is represented
57+ * as a two-dimensional array that can be treated as a table of state
58+ * transitions. Indexes are used to compress this array, taking
59+ * advantage of the fact that this array will always be very sparse.
60+ */
61+class BreakDictionary {
62+
63+ //=========================================================================
64+ // data members
65+ //=========================================================================
66+
67+ /**
68+ * The version of the dictionary that was read in.
69+ */
70+ private static int supportedVersion = 1;
71+
72+ /**
73+ * Maps from characters to column numbers. The main use of this is to
74+ * avoid making room in the array for empty columns.
75+ */
76+ private CompactByteArray columnMap = null;
77+ private SupplementaryCharacterData supplementaryCharColumnMap = null;
78+
79+ /**
80+ * The number of actual columns in the table
81+ */
82+ private int numCols;
83+
84+ /**
85+ * Columns are organized into groups of 32. This says how many
86+ * column groups. (We could calculate this, but we store the
87+ * value to avoid having to repeatedly calculate it.)
88+ */
89+ private int numColGroups;
90+
91+ /**
92+ * The actual compressed state table. Each conceptual row represents
93+ * a state, and the cells in it contain the row numbers of the states
94+ * to transition to for each possible letter. 0 is used to indicate
95+ * an illegal combination of letters (i.e., the error state). The
96+ * table is compressed by eliminating all the unpopulated (i.e., zero)
97+ * cells. Multiple conceptual rows can then be doubled up in a single
98+ * physical row by sliding them up and possibly shifting them to one
99+ * side or the other so the populated cells don't collide. Indexes
100+ * are used to identify unpopulated cells and to locate populated cells.
101+ */
102+ private short[] table = null;
103+
104+ /**
105+ * This index maps logical row numbers to physical row numbers
106+ */
107+ private short[] rowIndex = null;
108+
109+ /**
110+ * A bitmap is used to tell which cells in the comceptual table are
111+ * populated. This array contains all the unique bit combinations
112+ * in that bitmap. If the table is more than 32 columns wide,
113+ * successive entries in this array are used for a single row.
114+ */
115+ private int[] rowIndexFlags = null;
116+
117+ /**
118+ * This index maps from a logical row number into the bitmap table above.
119+ * (This keeps us from storing duplicate bitmap combinations.) Since there
120+ * are a lot of rows with only one populated cell, instead of wasting space
121+ * in the bitmap table, we just store a negative number in this index for
122+ * rows with one populated cell. The absolute value of that number is
123+ * the column number of the populated cell.
124+ */
125+ private short[] rowIndexFlagsIndex = null;
126+
127+ /**
128+ * For each logical row, this index contains a constant that is added to
129+ * the logical column number to get the physical column number
130+ */
131+ private byte[] rowIndexShifts = null;
132+
133+ //=========================================================================
134+ // deserialization
135+ //=========================================================================
136+
137+ public BreakDictionary(String dictionaryName)
138+ throws IOException, MissingResourceException {
139+
140+ readDictionaryFile(dictionaryName);
141+ }
142+
143+ private void readDictionaryFile(final String dictionaryName)
144+ throws IOException, MissingResourceException {
145+
146+ BufferedInputStream in;
147+ try {
148+ in = (BufferedInputStream)AccessController.doPrivileged(
149+ new PrivilegedExceptionAction() {
150+ public Object run() throws Exception {
151+ return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + dictionaryName));
152+ }
153+ }
154+ );
155+ }
156+ catch (PrivilegedActionException e) {
157+ throw new InternalError(e.toString());
158+ }
159+
160+ byte[] buf = new byte[8];
161+ if (in.read(buf) != 8) {
162+ throw new MissingResourceException("Wrong data length",
163+ dictionaryName, "");
164+ }
165+
166+ // check vesion
167+ int version = BreakIterator.getInt(buf, 0);
168+ if (version != supportedVersion) {
169+ throw new MissingResourceException("Dictionary version(" + version + ") is unsupported",
170+ dictionaryName, "");
171+ }
172+
173+ // get data size
174+ int len = BreakIterator.getInt(buf, 4);
175+ buf = new byte[len];
176+ if (in.read(buf) != len) {
177+ throw new MissingResourceException("Wrong data length",
178+ dictionaryName, "");
179+ }
180+
181+ // close the stream
182+ in.close();
183+
184+ int l;
185+ int offset = 0;
186+
187+ // read in the column map for BMP characteres (this is serialized in
188+ // its internal form: an index array followed by a data array)
189+ l = BreakIterator.getInt(buf, offset);
190+ offset += 4;
191+ short[] temp = new short[l];
192+ for (int i = 0; i < l; i++, offset+=2) {
193+ temp[i] = BreakIterator.getShort(buf, offset);
194+ }
195+ l = BreakIterator.getInt(buf, offset);
196+ offset += 4;
197+ byte[] temp2 = new byte[l];
198+ for (int i = 0; i < l; i++, offset++) {
199+ temp2[i] = buf[offset];
200+ }
201+ columnMap = new CompactByteArray(temp, temp2);
202+
203+ // read in numCols and numColGroups
204+ numCols = BreakIterator.getInt(buf, offset);
205+ offset += 4;
206+ numColGroups = BreakIterator.getInt(buf, offset);
207+ offset += 4;
208+
209+ // read in the row-number index
210+ l = BreakIterator.getInt(buf, offset);
211+ offset += 4;
212+ rowIndex = new short[l];
213+ for (int i = 0; i < l; i++, offset+=2) {
214+ rowIndex[i] = BreakIterator.getShort(buf, offset);
215+ }
216+
217+ // load in the populated-cells bitmap: index first, then bitmap list
218+ l = BreakIterator.getInt(buf, offset);
219+ offset += 4;
220+ rowIndexFlagsIndex = new short[l];
221+ for (int i = 0; i < l; i++, offset+=2) {
222+ rowIndexFlagsIndex[i] = BreakIterator.getShort(buf, offset);
223+ }
224+ l = BreakIterator.getInt(buf, offset);
225+ offset += 4;
226+ rowIndexFlags = new int[l];
227+ for (int i = 0; i < l; i++, offset+=4) {
228+ rowIndexFlags[i] = BreakIterator.getInt(buf, offset);
229+ }
230+
231+ // load in the row-shift index
232+ l = BreakIterator.getInt(buf, offset);
233+ offset += 4;
234+ rowIndexShifts = new byte[l];
235+ for (int i = 0; i < l; i++, offset++) {
236+ rowIndexShifts[i] = buf[offset];
237+ }
238+
239+ // load in the actual state table
240+ l = BreakIterator.getInt(buf, offset);
241+ offset += 4;
242+ table = new short[l];
243+ for (int i = 0; i < l; i++, offset+=2) {
244+ table[i] = BreakIterator.getShort(buf, offset);
245+ }
246+
247+ // finally, prepare the column map for supplementary characters
248+ l = BreakIterator.getInt(buf, offset);
249+ offset += 4;
250+ int[] temp3 = new int[l];
251+ for (int i = 0; i < l; i++, offset+=4) {
252+ temp3[i] = BreakIterator.getInt(buf, offset);
253+ }
254+ supplementaryCharColumnMap = new SupplementaryCharacterData(temp3);
255+ }
256+
257+ //=========================================================================
258+ // access to the words
259+ //=========================================================================
260+
261+ /**
262+ * Uses the column map to map the character to a column number, then
263+ * passes the row and column number to getNextState()
264+ * @param row The current state
265+ * @param ch The character whose column we're interested in
266+ * @return The new state to transition to
267+ */
268+ public final short getNextStateFromCharacter(int row, int ch) {
269+ int col;
270+ if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
271+ col = columnMap.elementAt((char)ch);
272+ } else {
273+ col = supplementaryCharColumnMap.getValue(ch);
274+ }
275+ return getNextState(row, col);
276+ }
277+
278+ /**
279+ * Returns the value in the cell with the specified (logical) row and
280+ * column numbers. In DictionaryBasedBreakIterator, the row number is
281+ * a state number, the column number is an input, and the return value
282+ * is the row number of the new state to transition to. (0 is the
283+ * "error" state, and -1 is the "end of word" state in a dictionary)
284+ * @param row The row number of the current state
285+ * @param col The column number of the input character (0 means "not a
286+ * dictionary character")
287+ * @return The row number of the new state to transition to
288+ */
289+ public final short getNextState(int row, int col) {
290+ if (cellIsPopulated(row, col)) {
291+ // we map from logical to physical row number by looking up the
292+ // mapping in rowIndex; we map from logical column number to
293+ // physical column number by looking up a shift value for this
294+ // logical row and offsetting the logical column number by
295+ // the shift amount. Then we can use internalAt() to actually
296+ // get the value out of the table.
297+ return internalAt(rowIndex[row], col + rowIndexShifts[row]);
298+ }
299+ else {
300+ return 0;
301+ }
302+ }
303+
304+ /**
305+ * Given (logical) row and column numbers, returns true if the
306+ * cell in that position is populated
307+ */
308+ private final boolean cellIsPopulated(int row, int col) {
309+ // look up the entry in the bitmap index for the specified row.
310+ // If it's a negative number, it's the column number of the only
311+ // populated cell in the row
312+ if (rowIndexFlagsIndex[row] < 0) {
313+ return col == -rowIndexFlagsIndex[row];
314+ }
315+
316+ // if it's a positive number, it's the offset of an entry in the bitmap
317+ // list. If the table is more than 32 columns wide, the bitmap is stored
318+ // successive entries in the bitmap list, so we have to divide the column
319+ // number by 32 and offset the number we got out of the index by the result.
320+ // Once we have the appropriate piece of the bitmap, test the appropriate
321+ // bit and return the result.
322+ else {
323+ int flags = rowIndexFlags[rowIndexFlagsIndex[row] + (col >> 5)];
324+ return (flags & (1 << (col & 0x1f))) != 0;
325+ }
326+ }
327+
328+ /**
329+ * Implementation of getNextState() when we know the specified cell is
330+ * populated.
331+ * @param row The PHYSICAL row number of the cell
332+ * @param col The PHYSICAL column number of the cell
333+ * @return The value stored in the cell
334+ */
335+ private final short internalAt(int row, int col) {
336+ // the table is a one-dimensional array, so this just does the math necessary
337+ // to treat it as a two-dimensional array (we don't just use a two-dimensional
338+ // array because two-dimensional arrays are inefficient in Java)
339+ return table[row * numCols + col];
340+ }
341+}
java/pkg/java/text/BreakIterator$1.class+0−0

Binary file not shown.

java/pkg/java/text/BreakIterator$BreakIteratorCache.class+0−0

Binary file not shown.

java/pkg/java/text/BreakIterator$BreakIteratorGetter.class+0−0

Binary file not shown.

java/pkg/java/text/BreakIterator.class+0−0

Binary file not shown.

java/pkg/java/text/BreakIterator.java+715−0
@@ -0,0 +1,715 @@
1+/*
2+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation
31+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
32+ * subsidiary of IBM. These materials are provided under terms
33+ * of a License Agreement between Taligent and Sun. This technology
34+ * is protected by multiple US and International patents.
35+ *
36+ * This notice and attribution to Taligent may not be removed.
37+ * Taligent is a registered trademark of Taligent, Inc.
38+ *
39+ */
40+
41+package java.text;
42+
43+import java.lang.ref.SoftReference;
44+import java.net.URL;
45+import java.io.InputStream;
46+import java.io.IOException;
47+import java.security.AccessController;
48+import java.security.PrivilegedAction;
49+import java.text.CharacterIterator;
50+import java.text.StringCharacterIterator;
51+import java.text.spi.BreakIteratorProvider;
52+import java.util.Locale;
53+import java.util.MissingResourceException;
54+import java.util.ResourceBundle;
55+import java.util.spi.LocaleServiceProvider;
56+import sun.util.LocaleServiceProviderPool;
57+import sun.util.resources.LocaleData;
58+
59+
60+/**
61+ * The <code>BreakIterator</code> class implements methods for finding
62+ * the location of boundaries in text. Instances of <code>BreakIterator</code>
63+ * maintain a current position and scan over text
64+ * returning the index of characters where boundaries occur.
65+ * Internally, <code>BreakIterator</code> scans text using a
66+ * <code>CharacterIterator</code>, and is thus able to scan text held
67+ * by any object implementing that protocol. A <code>StringCharacterIterator</code>
68+ * is used to scan <code>String</code> objects passed to <code>setText</code>.
69+ *
70+ * <p>
71+ * You use the factory methods provided by this class to create
72+ * instances of various types of break iterators. In particular,
73+ * use <code>getWordInstance</code>, <code>getLineInstance</code>,
74+ * <code>getSentenceInstance</code>, and <code>getCharacterInstance</code>
75+ * to create <code>BreakIterator</code>s that perform
76+ * word, line, sentence, and character boundary analysis respectively.
77+ * A single <code>BreakIterator</code> can work only on one unit
78+ * (word, line, sentence, and so on). You must use a different iterator
79+ * for each unit boundary analysis you wish to perform.
80+ *
81+ * <p><a name="line"></a>
82+ * Line boundary analysis determines where a text string can be
83+ * broken when line-wrapping. The mechanism correctly handles
84+ * punctuation and hyphenated words. Actual line breaking needs
85+ * to also consider the available line width and is handled by
86+ * higher-level software.
87+ *
88+ * <p><a name="sentence"></a>
89+ * Sentence boundary analysis allows selection with correct interpretation
90+ * of periods within numbers and abbreviations, and trailing punctuation
91+ * marks such as quotation marks and parentheses.
92+ *
93+ * <p><a name="word"></a>
94+ * Word boundary analysis is used by search and replace functions, as
95+ * well as within text editing applications that allow the user to
96+ * select words with a double click. Word selection provides correct
97+ * interpretation of punctuation marks within and following
98+ * words. Characters that are not part of a word, such as symbols
99+ * or punctuation marks, have word-breaks on both sides.
100+ *
101+ * <p><a name="character"></a>
102+ * Character boundary analysis allows users to interact with characters
103+ * as they expect to, for example, when moving the cursor through a text
104+ * string. Character boundary analysis provides correct navigation
105+ * through character strings, regardless of how the character is stored.
106+ * The boundaries returned may be those of supplementary characters,
107+ * combining character sequences, or ligature clusters.
108+ * For example, an accented character might be stored as a base character
109+ * and a diacritical mark. What users consider to be a character can
110+ * differ between languages.
111+ *
112+ * <p>
113+ * The <code>BreakIterator</code> instances returned by the factory methods
114+ * of this class are intended for use with natural languages only, not for
115+ * programming language text. It is however possible to define subclasses
116+ * that tokenize a programming language.
117+ *
118+ * <P>
119+ * <strong>Examples</strong>:<P>
120+ * Creating and using text boundaries:
121+ * <blockquote>
122+ * <pre>
123+ * public static void main(String args[]) {
124+ * if (args.length == 1) {
125+ * String stringToExamine = args[0];
126+ * //print each word in order
127+ * BreakIterator boundary = BreakIterator.getWordInstance();
128+ * boundary.setText(stringToExamine);
129+ * printEachForward(boundary, stringToExamine);
130+ * //print each sentence in reverse order
131+ * boundary = BreakIterator.getSentenceInstance(Locale.US);
132+ * boundary.setText(stringToExamine);
133+ * printEachBackward(boundary, stringToExamine);
134+ * printFirst(boundary, stringToExamine);
135+ * printLast(boundary, stringToExamine);
136+ * }
137+ * }
138+ * </pre>
139+ * </blockquote>
140+ *
141+ * Print each element in order:
142+ * <blockquote>
143+ * <pre>
144+ * public static void printEachForward(BreakIterator boundary, String source) {
145+ * int start = boundary.first();
146+ * for (int end = boundary.next();
147+ * end != BreakIterator.DONE;
148+ * start = end, end = boundary.next()) {
149+ * System.out.println(source.substring(start,end));
150+ * }
151+ * }
152+ * </pre>
153+ * </blockquote>
154+ *
155+ * Print each element in reverse order:
156+ * <blockquote>
157+ * <pre>
158+ * public static void printEachBackward(BreakIterator boundary, String source) {
159+ * int end = boundary.last();
160+ * for (int start = boundary.previous();
161+ * start != BreakIterator.DONE;
162+ * end = start, start = boundary.previous()) {
163+ * System.out.println(source.substring(start,end));
164+ * }
165+ * }
166+ * </pre>
167+ * </blockquote>
168+ *
169+ * Print first element:
170+ * <blockquote>
171+ * <pre>
172+ * public static void printFirst(BreakIterator boundary, String source) {
173+ * int start = boundary.first();
174+ * int end = boundary.next();
175+ * System.out.println(source.substring(start,end));
176+ * }
177+ * </pre>
178+ * </blockquote>
179+ *
180+ * Print last element:
181+ * <blockquote>
182+ * <pre>
183+ * public static void printLast(BreakIterator boundary, String source) {
184+ * int end = boundary.last();
185+ * int start = boundary.previous();
186+ * System.out.println(source.substring(start,end));
187+ * }
188+ * </pre>
189+ * </blockquote>
190+ *
191+ * Print the element at a specified position:
192+ * <blockquote>
193+ * <pre>
194+ * public static void printAt(BreakIterator boundary, int pos, String source) {
195+ * int end = boundary.following(pos);
196+ * int start = boundary.previous();
197+ * System.out.println(source.substring(start,end));
198+ * }
199+ * </pre>
200+ * </blockquote>
201+ *
202+ * Find the next word:
203+ * <blockquote>
204+ * <pre>
205+ * public static int nextWordStartAfter(int pos, String text) {
206+ * BreakIterator wb = BreakIterator.getWordInstance();
207+ * wb.setText(text);
208+ * int last = wb.following(pos);
209+ * int current = wb.next();
210+ * while (current != BreakIterator.DONE) {
211+ * for (int p = last; p < current; p++) {
212+ * if (Character.isLetter(text.codePointAt(p)))
213+ * return last;
214+ * }
215+ * last = current;
216+ * current = wb.next();
217+ * }
218+ * return BreakIterator.DONE;
219+ * }
220+ * </pre>
221+ * (The iterator returned by BreakIterator.getWordInstance() is unique in that
222+ * the break positions it returns don't represent both the start and end of the
223+ * thing being iterated over. That is, a sentence-break iterator returns breaks
224+ * that each represent the end of one sentence and the beginning of the next.
225+ * With the word-break iterator, the characters between two boundaries might be a
226+ * word, or they might be the punctuation or whitespace between two words. The
227+ * above code uses a simple heuristic to determine which boundary is the beginning
228+ * of a word: If the characters between this boundary and the next boundary
229+ * include at least one letter (this can be an alphabetical letter, a CJK ideograph,
230+ * a Hangul syllable, a Kana character, etc.), then the text between this boundary
231+ * and the next is a word; otherwise, it's the material between words.)
232+ * </blockquote>
233+ *
234+ * @see CharacterIterator
235+ *
236+ */
237+
238+public abstract class BreakIterator implements Cloneable
239+{
240+ /**
241+ * Constructor. BreakIterator is stateless and has no default behavior.
242+ */
243+ protected BreakIterator()
244+ {
245+ }
246+
247+ /**
248+ * Create a copy of this iterator
249+ * @return A copy of this
250+ */
251+ public Object clone()
252+ {
253+ try {
254+ return super.clone();
255+ }
256+ catch (CloneNotSupportedException e) {
257+ throw new InternalError();
258+ }
259+ }
260+
261+ /**
262+ * DONE is returned by previous(), next(), next(int), preceding(int)
263+ * and following(int) when either the first or last text boundary has been
264+ * reached.
265+ */
266+ public static final int DONE = -1;
267+
268+ /**
269+ * Returns the first boundary. The iterator's current position is set
270+ * to the first text boundary.
271+ * @return The character index of the first text boundary.
272+ */
273+ public abstract int first();
274+
275+ /**
276+ * Returns the last boundary. The iterator's current position is set
277+ * to the last text boundary.
278+ * @return The character index of the last text boundary.
279+ */
280+ public abstract int last();
281+
282+ /**
283+ * Returns the nth boundary from the current boundary. If either
284+ * the first or last text boundary has been reached, it returns
285+ * <code>BreakIterator.DONE</code> and the current position is set to either
286+ * the first or last text boundary depending on which one is reached. Otherwise,
287+ * the iterator's current position is set to the new boundary.
288+ * For example, if the iterator's current position is the mth text boundary
289+ * and three more boundaries exist from the current boundary to the last text
290+ * boundary, the next(2) call will return m + 2. The new text position is set
291+ * to the (m + 2)th text boundary. A next(4) call would return
292+ * <code>BreakIterator.DONE</code> and the last text boundary would become the
293+ * new text position.
294+ * @param n which boundary to return. A value of 0
295+ * does nothing. Negative values move to previous boundaries
296+ * and positive values move to later boundaries.
297+ * @return The character index of the nth boundary from the current position
298+ * or <code>BreakIterator.DONE</code> if either first or last text boundary
299+ * has been reached.
300+ */
301+ public abstract int next(int n);
302+
303+ /**
304+ * Returns the boundary following the current boundary. If the current boundary
305+ * is the last text boundary, it returns <code>BreakIterator.DONE</code> and
306+ * the iterator's current position is unchanged. Otherwise, the iterator's
307+ * current position is set to the boundary following the current boundary.
308+ * @return The character index of the next text boundary or
309+ * <code>BreakIterator.DONE</code> if the current boundary is the last text
310+ * boundary.
311+ * Equivalent to next(1).
312+ * @see #next(int)
313+ */
314+ public abstract int next();
315+
316+ /**
317+ * Returns the boundary preceding the current boundary. If the current boundary
318+ * is the first text boundary, it returns <code>BreakIterator.DONE</code> and
319+ * the iterator's current position is unchanged. Otherwise, the iterator's
320+ * current position is set to the boundary preceding the current boundary.
321+ * @return The character index of the previous text boundary or
322+ * <code>BreakIterator.DONE</code> if the current boundary is the first text
323+ * boundary.
324+ */
325+ public abstract int previous();
326+
327+ /**
328+ * Returns the first boundary following the specified character offset. If the
329+ * specified offset equals to the last text boundary, it returns
330+ * <code>BreakIterator.DONE</code> and the iterator's current position is unchanged.
331+ * Otherwise, the iterator's current position is set to the returned boundary.
332+ * The value returned is always greater than the offset or the value
333+ * <code>BreakIterator.DONE</code>.
334+ * @param offset the character offset to begin scanning.
335+ * @return The first boundary after the specified offset or
336+ * <code>BreakIterator.DONE</code> if the last text boundary is passed in
337+ * as the offset.
338+ * @exception IllegalArgumentException if the specified offset is less than
339+ * the first text boundary or greater than the last text boundary.
340+ */
341+ public abstract int following(int offset);
342+
343+ /**
344+ * Returns the last boundary preceding the specified character offset. If the
345+ * specified offset equals to the first text boundary, it returns
346+ * <code>BreakIterator.DONE</code> and the iterator's current position is unchanged.
347+ * Otherwise, the iterator's current position is set to the returned boundary.
348+ * The value returned is always less than the offset or the value
349+ * <code>BreakIterator.DONE</code>.
350+ * @param offset the characater offset to begin scanning.
351+ * @return The last boundary before the specified offset or
352+ * <code>BreakIterator.DONE</code> if the first text boundary is passed in
353+ * as the offset.
354+ * @exception IllegalArgumentException if the specified offset is less than
355+ * the first text boundary or greater than the last text boundary.
356+ * @since 1.2
357+ */
358+ public int preceding(int offset) {
359+ // NOTE: This implementation is here solely because we can't add new
360+ // abstract methods to an existing class. There is almost ALWAYS a
361+ // better, faster way to do this.
362+ int pos = following(offset);
363+ while (pos >= offset && pos != DONE)
364+ pos = previous();
365+ return pos;
366+ }
367+
368+ /**
369+ * Returns true if the specified character offset is a text boundary.
370+ * @param offset the character offset to check.
371+ * @return <code>true</code> if "offset" is a boundary position,
372+ * <code>false</code> otherwise.
373+ * @exception IllegalArgumentException if the specified offset is less than
374+ * the first text boundary or greater than the last text boundary.
375+ * @since 1.2
376+ */
377+ public boolean isBoundary(int offset) {
378+ // NOTE: This implementation probably is wrong for most situations
379+ // because it fails to take into account the possibility that a
380+ // CharacterIterator passed to setText() may not have a begin offset
381+ // of 0. But since the abstract BreakIterator doesn't have that
382+ // knowledge, it assumes the begin offset is 0. If you subclass
383+ // BreakIterator, copy the SimpleTextBoundary implementation of this
384+ // function into your subclass. [This should have been abstract at
385+ // this level, but it's too late to fix that now.]
386+ if (offset == 0) {
387+ return true;
388+ }
389+ int boundary = following(offset - 1);
390+ if (boundary == DONE) {
391+ throw new IllegalArgumentException();
392+ }
393+ return boundary == offset;
394+ }
395+
396+ /**
397+ * Returns character index of the text boundary that was most
398+ * recently returned by next(), next(int), previous(), first(), last(),
399+ * following(int) or preceding(int). If any of these methods returns
400+ * <code>BreakIterator.DONE</code> because either first or last text boundary
401+ * has been reached, it returns the first or last text boundary depending on
402+ * which one is reached.
403+ * @return The text boundary returned from the above methods, first or last
404+ * text boundary.
405+ * @see #next()
406+ * @see #next(int)
407+ * @see #previous()
408+ * @see #first()
409+ * @see #last()
410+ * @see #following(int)
411+ * @see #preceding(int)
412+ */
413+ public abstract int current();
414+
415+ /**
416+ * Get the text being scanned
417+ * @return the text being scanned
418+ */
419+ public abstract CharacterIterator getText();
420+
421+ /**
422+ * Set a new text string to be scanned. The current scan
423+ * position is reset to first().
424+ * @param newText new text to scan.
425+ */
426+ public void setText(String newText)
427+ {
428+ setText(new StringCharacterIterator(newText));
429+ }
430+
431+ /**
432+ * Set a new text for scanning. The current scan
433+ * position is reset to first().
434+ * @param newText new text to scan.
435+ */
436+ public abstract void setText(CharacterIterator newText);
437+
438+ private static final int CHARACTER_INDEX = 0;
439+ private static final int WORD_INDEX = 1;
440+ private static final int LINE_INDEX = 2;
441+ private static final int SENTENCE_INDEX = 3;
442+ private static final SoftReference[] iterCache = new SoftReference[4];
443+
444+ /**
445+ * Returns a new <code>BreakIterator</code> instance
446+ * for <a href="#word">word breaks</a>
447+ * for the {@linkplain Locale#getDefault() default locale}.
448+ * @return A break iterator for word breaks
449+ */
450+ public static BreakIterator getWordInstance()
451+ {
452+ return getWordInstance(Locale.getDefault());
453+ }
454+
455+ /**
456+ * Returns a new <code>BreakIterator</code> instance
457+ * for <a href="#word">word breaks</a>
458+ * for the given locale.
459+ * @param locale the desired locale
460+ * @return A break iterator for word breaks
461+ * @exception NullPointerException if <code>locale</code> is null
462+ */
463+ public static BreakIterator getWordInstance(Locale locale)
464+ {
465+ return getBreakInstance(locale,
466+ WORD_INDEX,
467+ "WordData",
468+ "WordDictionary");
469+ }
470+
471+ /**
472+ * Returns a new <code>BreakIterator</code> instance
473+ * for <a href="#line">line breaks</a>
474+ * for the {@linkplain Locale#getDefault() default locale}.
475+ * @return A break iterator for line breaks
476+ */
477+ public static BreakIterator getLineInstance()
478+ {
479+ return getLineInstance(Locale.getDefault());
480+ }
481+
482+ /**
483+ * Returns a new <code>BreakIterator</code> instance
484+ * for <a href="#line">line breaks</a>
485+ * for the given locale.
486+ * @param locale the desired locale
487+ * @return A break iterator for line breaks
488+ * @exception NullPointerException if <code>locale</code> is null
489+ */
490+ public static BreakIterator getLineInstance(Locale locale)
491+ {
492+ return getBreakInstance(locale,
493+ LINE_INDEX,
494+ "LineData",
495+ "LineDictionary");
496+ }
497+
498+ /**
499+ * Returns a new <code>BreakIterator</code> instance
500+ * for <a href="#character">character breaks</a>
501+ * for the {@linkplain Locale#getDefault() default locale}.
502+ * @return A break iterator for character breaks
503+ */
504+ public static BreakIterator getCharacterInstance()
505+ {
506+ return getCharacterInstance(Locale.getDefault());
507+ }
508+
509+ /**
510+ * Returns a new <code>BreakIterator</code> instance
511+ * for <a href="#character">character breaks</a>
512+ * for the given locale.
513+ * @param locale the desired locale
514+ * @return A break iterator for character breaks
515+ * @exception NullPointerException if <code>locale</code> is null
516+ */
517+ public static BreakIterator getCharacterInstance(Locale locale)
518+ {
519+ return getBreakInstance(locale,
520+ CHARACTER_INDEX,
521+ "CharacterData",
522+ "CharacterDictionary");
523+ }
524+
525+ /**
526+ * Returns a new <code>BreakIterator</code> instance
527+ * for <a href="#sentence">sentence breaks</a>
528+ * for the {@linkplain Locale#getDefault() default locale}.
529+ * @return A break iterator for sentence breaks
530+ */
531+ public static BreakIterator getSentenceInstance()
532+ {
533+ return getSentenceInstance(Locale.getDefault());
534+ }
535+
536+ /**
537+ * Returns a new <code>BreakIterator</code> instance
538+ * for <a href="#sentence">sentence breaks</a>
539+ * for the given locale.
540+ * @param locale the desired locale
541+ * @return A break iterator for sentence breaks
542+ * @exception NullPointerException if <code>locale</code> is null
543+ */
544+ public static BreakIterator getSentenceInstance(Locale locale)
545+ {
546+ return getBreakInstance(locale,
547+ SENTENCE_INDEX,
548+ "SentenceData",
549+ "SentenceDictionary");
550+ }
551+
552+ private static BreakIterator getBreakInstance(Locale locale,
553+ int type,
554+ String dataName,
555+ String dictionaryName) {
556+ if (iterCache[type] != null) {
557+ BreakIteratorCache cache = (BreakIteratorCache) iterCache[type].get();
558+ if (cache != null) {
559+ if (cache.getLocale().equals(locale)) {
560+ return cache.createBreakInstance();
561+ }
562+ }
563+ }
564+
565+ BreakIterator result = createBreakInstance(locale,
566+ type,
567+ dataName,
568+ dictionaryName);
569+ BreakIteratorCache cache = new BreakIteratorCache(locale, result);
570+ iterCache[type] = new SoftReference(cache);
571+ return result;
572+ }
573+
574+ private static ResourceBundle getBundle(final String baseName, final Locale locale) {
575+ return (ResourceBundle) AccessController.doPrivileged(new PrivilegedAction() {
576+ public Object run() {
577+ return ResourceBundle.getBundle(baseName, locale);
578+ }
579+ });
580+ }
581+
582+ private static BreakIterator createBreakInstance(Locale locale,
583+ int type,
584+ String dataName,
585+ String dictionaryName) {
586+
587+ // Check whether a provider can provide an implementation that's closer
588+ // to the requested locale than what the Java runtime itself can provide.
589+ LocaleServiceProviderPool pool =
590+ LocaleServiceProviderPool.getPool(BreakIteratorProvider.class);
591+ if (pool.hasProviders()) {
592+ BreakIterator providersInstance = pool.getLocalizedObject(
593+ BreakIteratorGetter.INSTANCE,
594+ locale, type);
595+ if (providersInstance != null) {
596+ return providersInstance;
597+ }
598+ }
599+
600+ ResourceBundle bundle = getBundle(
601+ "sun.text.resources.BreakIteratorInfo", locale);
602+ String[] classNames = bundle.getStringArray("BreakIteratorClasses");
603+
604+ String dataFile = bundle.getString(dataName);
605+
606+ try {
607+ if (classNames[type].equals("RuleBasedBreakIterator")) {
608+ return new RuleBasedBreakIterator(dataFile);
609+ }
610+ else if (classNames[type].equals("DictionaryBasedBreakIterator")) {
611+ String dictionaryFile = bundle.getString(dictionaryName);
612+ return new DictionaryBasedBreakIterator(dataFile, dictionaryFile);
613+ }
614+ else {
615+ throw new IllegalArgumentException("Invalid break iterator class \"" +
616+ classNames[type] + "\"");
617+ }
618+ }
619+ catch (Exception e) {
620+ throw new InternalError(e.toString());
621+ }
622+ }
623+
624+ /**
625+ * Returns an array of all locales for which the
626+ * <code>get*Instance</code> methods of this class can return
627+ * localized instances.
628+ * The returned array represents the union of locales supported by the Java
629+ * runtime and by installed
630+ * {@link java.text.spi.BreakIteratorProvider BreakIteratorProvider} implementations.
631+ * It must contain at least a <code>Locale</code>
632+ * instance equal to {@link java.util.Locale#US Locale.US}.
633+ *
634+ * @return An array of locales for which localized
635+ * <code>BreakIterator</code> instances are available.
636+ */
637+ public static synchronized Locale[] getAvailableLocales()
638+ {
639+ LocaleServiceProviderPool pool =
640+ LocaleServiceProviderPool.getPool(BreakIteratorProvider.class);
641+ return pool.getAvailableLocales();
642+ }
643+
644+ private static final class BreakIteratorCache {
645+
646+ private BreakIterator iter;
647+ private Locale locale;
648+
649+ BreakIteratorCache(Locale locale, BreakIterator iter) {
650+ this.locale = locale;
651+ this.iter = (BreakIterator) iter.clone();
652+ }
653+
654+ Locale getLocale() {
655+ return locale;
656+ }
657+
658+ BreakIterator createBreakInstance() {
659+ return (BreakIterator) iter.clone();
660+ }
661+ }
662+
663+ static long getLong(byte[] buf, int offset) {
664+ long num = buf[offset]&0xFF;
665+ for (int i = 1; i < 8; i++) {
666+ num = num<<8 | (buf[offset+i]&0xFF);
667+ }
668+ return num;
669+ }
670+
671+ static int getInt(byte[] buf, int offset) {
672+ int num = buf[offset]&0xFF;
673+ for (int i = 1; i < 4; i++) {
674+ num = num<<8 | (buf[offset+i]&0xFF);
675+ }
676+ return num;
677+ }
678+
679+ static short getShort(byte[] buf, int offset) {
680+ short num = (short)(buf[offset]&0xFF);
681+ num = (short)(num<<8 | (buf[offset+1]&0xFF));
682+ return num;
683+ }
684+
685+ /**
686+ * Obtains a BreakIterator instance from a BreakIteratorProvider
687+ * implementation.
688+ */
689+ private static class BreakIteratorGetter
690+ implements LocaleServiceProviderPool.LocalizedObjectGetter<BreakIteratorProvider, BreakIterator> {
691+ private static final BreakIteratorGetter INSTANCE =
692+ new BreakIteratorGetter();
693+
694+ public BreakIterator getObject(BreakIteratorProvider breakIteratorProvider,
695+ Locale locale,
696+ String key,
697+ Object... params) {
698+ assert params.length == 1;
699+
700+ switch ((Integer)params[0]) {
701+ case CHARACTER_INDEX:
702+ return breakIteratorProvider.getCharacterInstance(locale);
703+ case WORD_INDEX:
704+ return breakIteratorProvider.getWordInstance(locale);
705+ case LINE_INDEX:
706+ return breakIteratorProvider.getLineInstance(locale);
707+ case SENTENCE_INDEX:
708+ return breakIteratorProvider.getSentenceInstance(locale);
709+ default:
710+ assert false : "should not happen";
711+ }
712+ return null;
713+ }
714+ }
715+}
java/pkg/java/text/CalendarBuilder.class+0−0

Binary file not shown.

java/pkg/java/text/CalendarBuilder.java+170−0
@@ -0,0 +1,170 @@
1+/*
2+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.text;
27+
28+import java.util.Calendar;
29+import static java.util.GregorianCalendar.*;
30+
31+/**
32+ * {@code CalendarBuilder} keeps field-value pairs for setting
33+ * the calendar fields of the given {@code Calendar}. It has the
34+ * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
35+ * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
36+ * {@code DAY_OF_WEEK} in the ISO day of week numbering.
37+ *
38+ * <p>{@code CalendarBuilder} retains the semantic of the pseudo
39+ * timestamp for fields. {@code CalendarBuilder} uses a single
40+ * int array combining fields[] and stamp[] of {@code Calendar}.
41+ *
42+ * @author Masayoshi Okutsu
43+ */
44+class CalendarBuilder {
45+ /*
46+ * Pseudo time stamp constants used in java.util.Calendar
47+ */
48+ private static final int UNSET = 0;
49+ private static final int COMPUTED = 1;
50+ private static final int MINIMUM_USER_STAMP = 2;
51+
52+ private static final int MAX_FIELD = FIELD_COUNT + 1;
53+
54+ public static final int WEEK_YEAR = FIELD_COUNT;
55+ public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
56+
57+ // stamp[] (lower half) and field[] (upper half) combined
58+ private final int[] field;
59+ private int nextStamp;
60+ private int maxFieldIndex;
61+
62+ CalendarBuilder() {
63+ field = new int[MAX_FIELD * 2];
64+ nextStamp = MINIMUM_USER_STAMP;
65+ maxFieldIndex = -1;
66+ }
67+
68+ CalendarBuilder set(int index, int value) {
69+ if (index == ISO_DAY_OF_WEEK) {
70+ index = DAY_OF_WEEK;
71+ value = toCalendarDayOfWeek(value);
72+ }
73+ field[index] = nextStamp++;
74+ field[MAX_FIELD + index] = value;
75+ if (index > maxFieldIndex && index < FIELD_COUNT) {
76+ maxFieldIndex = index;
77+ }
78+ return this;
79+ }
80+
81+ CalendarBuilder addYear(int value) {
82+ field[MAX_FIELD + YEAR] += value;
83+ field[MAX_FIELD + WEEK_YEAR] += value;
84+ return this;
85+ }
86+
87+ boolean isSet(int index) {
88+ if (index == ISO_DAY_OF_WEEK) {
89+ index = DAY_OF_WEEK;
90+ }
91+ return field[index] > UNSET;
92+ }
93+
94+ Calendar establish(Calendar cal) {
95+ boolean weekDate = isSet(WEEK_YEAR)
96+ && field[WEEK_YEAR] > field[YEAR];
97+ if (weekDate && !cal.isWeekDateSupported()) {
98+ // Use YEAR instead
99+ if (!isSet(YEAR)) {
100+ set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
101+ }
102+ weekDate = false;
103+ }
104+
105+ cal.clear();
106+ // Set the fields from the min stamp to the max stamp so that
107+ // the field resolution works in the Calendar.
108+ for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
109+ for (int index = 0; index <= maxFieldIndex; index++) {
110+ if (field[index] == stamp) {
111+ cal.set(index, field[MAX_FIELD + index]);
112+ break;
113+ }
114+ }
115+ }
116+
117+ if (weekDate) {
118+ int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
119+ int dayOfWeek = isSet(DAY_OF_WEEK) ?
120+ field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
121+ if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
122+ if (dayOfWeek >= 8) {
123+ dayOfWeek--;
124+ weekOfYear += dayOfWeek / 7;
125+ dayOfWeek = (dayOfWeek % 7) + 1;
126+ } else {
127+ while (dayOfWeek <= 0) {
128+ dayOfWeek += 7;
129+ weekOfYear--;
130+ }
131+ }
132+ dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
133+ }
134+ cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
135+ }
136+ return cal;
137+ }
138+
139+ public String toString() {
140+ StringBuilder sb = new StringBuilder();
141+ sb.append("CalendarBuilder:[");
142+ for (int i = 0; i < field.length; i++) {
143+ if (isSet(i)) {
144+ sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
145+ }
146+ }
147+ int lastIndex = sb.length() - 1;
148+ if (sb.charAt(lastIndex) == ',') {
149+ sb.setLength(lastIndex);
150+ }
151+ sb.append(']');
152+ return sb.toString();
153+ }
154+
155+ static int toISODayOfWeek(int calendarDayOfWeek) {
156+ return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
157+ }
158+
159+ static int toCalendarDayOfWeek(int isoDayOfWeek) {
160+ if (!isValidDayOfWeek(isoDayOfWeek)) {
161+ // adjust later for lenient mode
162+ return isoDayOfWeek;
163+ }
164+ return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
165+ }
166+
167+ static boolean isValidDayOfWeek(int dayOfWeek) {
168+ return dayOfWeek > 0 && dayOfWeek <= 7;
169+ }
170+}
java/pkg/java/text/CharacterIterator.class+0−0

Binary file not shown.

java/pkg/java/text/CharacterIterator.java+193−0
@@ -0,0 +1,193 @@
1+/*
2+ * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation
31+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
32+ * subsidiary of IBM. These materials are provided under terms
33+ * of a License Agreement between Taligent and Sun. This technology
34+ * is protected by multiple US and International patents.
35+ *
36+ * This notice and attribution to Taligent may not be removed.
37+ * Taligent is a registered trademark of Taligent, Inc.
38+ *
39+ */
40+
41+package java.text;
42+
43+
44+/**
45+ * This interface defines a protocol for bidirectional iteration over text.
46+ * The iterator iterates over a bounded sequence of characters. Characters
47+ * are indexed with values beginning with the value returned by getBeginIndex() and
48+ * continuing through the value returned by getEndIndex()-1.
49+ * <p>
50+ * Iterators maintain a current character index, whose valid range is from
51+ * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
52+ * handling of zero-length text ranges and for historical reasons.
53+ * The current index can be retrieved by calling getIndex() and set directly
54+ * by calling setIndex(), first(), and last().
55+ * <p>
56+ * The methods previous() and next() are used for iteration. They return DONE if
57+ * they would move outside the range from getBeginIndex() to getEndIndex() -1,
58+ * signaling that the iterator has reached the end of the sequence. DONE is
59+ * also returned by other methods to indicate that the current index is
60+ * outside this range.
61+ *
62+ * <P>Examples:<P>
63+ *
64+ * Traverse the text from start to finish
65+ * <pre>
66+ * public void traverseForward(CharacterIterator iter) {
67+ * for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
68+ * processChar(c);
69+ * }
70+ * }
71+ * </pre>
72+ *
73+ * Traverse the text backwards, from end to start
74+ * <pre>
75+ * public void traverseBackward(CharacterIterator iter) {
76+ * for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
77+ * processChar(c);
78+ * }
79+ * }
80+ * </pre>
81+ *
82+ * Traverse both forward and backward from a given position in the text.
83+ * Calls to notBoundary() in this example represents some
84+ * additional stopping criteria.
85+ * <pre>
86+ * public void traverseOut(CharacterIterator iter, int pos) {
87+ * for (char c = iter.setIndex(pos);
88+ * c != CharacterIterator.DONE && notBoundary(c);
89+ * c = iter.next()) {
90+ * }
91+ * int end = iter.getIndex();
92+ * for (char c = iter.setIndex(pos);
93+ * c != CharacterIterator.DONE && notBoundary(c);
94+ * c = iter.previous()) {
95+ * }
96+ * int start = iter.getIndex();
97+ * processSection(start, end);
98+ * }
99+ * </pre>
100+ *
101+ * @see StringCharacterIterator
102+ * @see AttributedCharacterIterator
103+ */
104+
105+public interface CharacterIterator extends Cloneable
106+{
107+
108+ /**
109+ * Constant that is returned when the iterator has reached either the end
110+ * or the beginning of the text. The value is '\\uFFFF', the "not a
111+ * character" value which should not occur in any valid Unicode string.
112+ */
113+ public static final char DONE = '\uFFFF';
114+
115+ /**
116+ * Sets the position to getBeginIndex() and returns the character at that
117+ * position.
118+ * @return the first character in the text, or DONE if the text is empty
119+ * @see #getBeginIndex()
120+ */
121+ public char first();
122+
123+ /**
124+ * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
125+ * and returns the character at that position.
126+ * @return the last character in the text, or DONE if the text is empty
127+ * @see #getEndIndex()
128+ */
129+ public char last();
130+
131+ /**
132+ * Gets the character at the current position (as returned by getIndex()).
133+ * @return the character at the current position or DONE if the current
134+ * position is off the end of the text.
135+ * @see #getIndex()
136+ */
137+ public char current();
138+
139+ /**
140+ * Increments the iterator's index by one and returns the character
141+ * at the new index. If the resulting index is greater or equal
142+ * to getEndIndex(), the current index is reset to getEndIndex() and
143+ * a value of DONE is returned.
144+ * @return the character at the new position or DONE if the new
145+ * position is off the end of the text range.
146+ */
147+ public char next();
148+
149+ /**
150+ * Decrements the iterator's index by one and returns the character
151+ * at the new index. If the current index is getBeginIndex(), the index
152+ * remains at getBeginIndex() and a value of DONE is returned.
153+ * @return the character at the new position or DONE if the current
154+ * position is equal to getBeginIndex().
155+ */
156+ public char previous();
157+
158+ /**
159+ * Sets the position to the specified position in the text and returns that
160+ * character.
161+ * @param position the position within the text. Valid values range from
162+ * getBeginIndex() to getEndIndex(). An IllegalArgumentException is thrown
163+ * if an invalid value is supplied.
164+ * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
165+ */
166+ public char setIndex(int position);
167+
168+ /**
169+ * Returns the start index of the text.
170+ * @return the index at which the text begins.
171+ */
172+ public int getBeginIndex();
173+
174+ /**
175+ * Returns the end index of the text. This index is the index of the first
176+ * character following the end of the text.
177+ * @return the index after the last character in the text
178+ */
179+ public int getEndIndex();
180+
181+ /**
182+ * Returns the current index.
183+ * @return the current index.
184+ */
185+ public int getIndex();
186+
187+ /**
188+ * Create a copy of this iterator
189+ * @return A copy of this
190+ */
191+ public Object clone();
192+
193+}
java/pkg/java/text/CharacterIteratorFieldDelegate.class+0−0

Binary file not shown.

java/pkg/java/text/CharacterIteratorFieldDelegate.java+124−0
@@ -0,0 +1,124 @@
1+/*
2+ * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package java.text;
26+
27+import java.util.ArrayList;
28+
29+/**
30+ * CharacterIteratorFieldDelegate combines the notifications from a Format
31+ * into a resulting <code>AttributedCharacterIterator</code>. The resulting
32+ * <code>AttributedCharacterIterator</code> can be retrieved by way of
33+ * the <code>getIterator</code> method.
34+ *
35+ */
36+class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
37+ /**
38+ * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
39+ * for a region > size, a new instance of AttributedString is added to
40+ * attributedStrings. Subsequent invocations of <code>formatted</code>
41+ * for existing regions result in invoking addAttribute on the existing
42+ * AttributedStrings.
43+ */
44+ private ArrayList attributedStrings;
45+ /**
46+ * Running count of the number of characters that have
47+ * been encountered.
48+ */
49+ private int size;
50+
51+
52+ CharacterIteratorFieldDelegate() {
53+ attributedStrings = new ArrayList();
54+ }
55+
56+ public void formatted(Format.Field attr, Object value, int start, int end,
57+ StringBuffer buffer) {
58+ if (start != end) {
59+ if (start < size) {
60+ // Adjust attributes of existing runs
61+ int index = size;
62+ int asIndex = attributedStrings.size() - 1;
63+
64+ while (start < index) {
65+ AttributedString as = (AttributedString)attributedStrings.
66+ get(asIndex--);
67+ int newIndex = index - as.length();
68+ int aStart = Math.max(0, start - newIndex);
69+
70+ as.addAttribute(attr, value, aStart, Math.min(
71+ end - start, as.length() - aStart) +
72+ aStart);
73+ index = newIndex;
74+ }
75+ }
76+ if (size < start) {
77+ // Pad attributes
78+ attributedStrings.add(new AttributedString(
79+ buffer.substring(size, start)));
80+ size = start;
81+ }
82+ if (size < end) {
83+ // Add new string
84+ int aStart = Math.max(start, size);
85+ AttributedString string = new AttributedString(
86+ buffer.substring(aStart, end));
87+
88+ string.addAttribute(attr, value);
89+ attributedStrings.add(string);
90+ size = end;
91+ }
92+ }
93+ }
94+
95+ public void formatted(int fieldID, Format.Field attr, Object value,
96+ int start, int end, StringBuffer buffer) {
97+ formatted(attr, value, start, end, buffer);
98+ }
99+
100+ /**
101+ * Returns an <code>AttributedCharacterIterator</code> that can be used
102+ * to iterate over the resulting formatted String.
103+ *
104+ * @pararm string Result of formatting.
105+ */
106+ public AttributedCharacterIterator getIterator(String string) {
107+ // Add the last AttributedCharacterIterator if necessary
108+ // assert(size <= string.length());
109+ if (string.length() > size) {
110+ attributedStrings.add(new AttributedString(
111+ string.substring(size)));
112+ size = string.length();
113+ }
114+ int iCount = attributedStrings.size();
115+ AttributedCharacterIterator iterators[] = new
116+ AttributedCharacterIterator[iCount];
117+
118+ for (int counter = 0; counter < iCount; counter++) {
119+ iterators[counter] = ((AttributedString)attributedStrings.
120+ get(counter)).getIterator();
121+ }
122+ return new AttributedString(iterators).getIterator();
123+ }
124+}
java/pkg/java/text/ChoiceFormat.class+0−0

Binary file not shown.

java/pkg/java/text/ChoiceFormat.java+619−0
@@ -0,0 +1,619 @@
1+/*
2+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.InvalidObjectException;
42+import java.io.IOException;
43+import java.io.ObjectInputStream;
44+import java.util.Arrays;
45+
46+/**
47+ * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
48+ * It is generally used in a <code>MessageFormat</code> for handling plurals.
49+ * The choice is specified with an ascending list of doubles, where each item
50+ * specifies a half-open interval up to the next item:
51+ * <blockquote>
52+ * <pre>
53+ * X matches j if and only if limit[j] &lt;= X &lt; limit[j+1]
54+ * </pre>
55+ * </blockquote>
56+ * If there is no match, then either the first or last index is used, depending
57+ * on whether the number (X) is too low or too high. If the limit array is not
58+ * in ascending order, the results of formatting will be incorrect. ChoiceFormat
59+ * also accepts <code>&#92;u221E</code> as equivalent to infinity(INF).
60+ *
61+ * <p>
62+ * <strong>Note:</strong>
63+ * <code>ChoiceFormat</code> differs from the other <code>Format</code>
64+ * classes in that you create a <code>ChoiceFormat</code> object with a
65+ * constructor (not with a <code>getInstance</code> style factory
66+ * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
67+ * doesn't require any complex setup for a given locale. In fact,
68+ * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
69+ *
70+ * <p>
71+ * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
72+ * and an array of limits. The length of these arrays must be the same.
73+ * For example,
74+ * <ul>
75+ * <li>
76+ * <em>limits</em> = {1,2,3,4,5,6,7}<br>
77+ * <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
78+ * <li>
79+ * <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
80+ * <em>formats</em> = {"no files", "one file", "many files"}<br>
81+ * (<code>nextDouble</code> can be used to get the next higher double, to
82+ * make the half-open interval.)
83+ * </ul>
84+ *
85+ * <p>
86+ * Here is a simple example that shows formatting and parsing:
87+ * <blockquote>
88+ * <pre>
89+ * double[] limits = {1,2,3,4,5,6,7};
90+ * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
91+ * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
92+ * ParsePosition status = new ParsePosition(0);
93+ * for (double i = 0.0; i &lt;= 8.0; ++i) {
94+ * status.setIndex(0);
95+ * System.out.println(i + " -&gt; " + form.format(i) + " -&gt; "
96+ * + form.parse(form.format(i),status));
97+ * }
98+ * </pre>
99+ * </blockquote>
100+ * Here is a more complex example, with a pattern format:
101+ * <blockquote>
102+ * <pre>
103+ * double[] filelimits = {0,1,2};
104+ * String[] filepart = {"are no files","is one file","are {2} files"};
105+ * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
106+ * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
107+ * MessageFormat pattform = new MessageFormat("There {0} on {1}");
108+ * pattform.setFormats(testFormats);
109+ * Object[] testArgs = {null, "ADisk", null};
110+ * for (int i = 0; i &lt; 4; ++i) {
111+ * testArgs[0] = new Integer(i);
112+ * testArgs[2] = testArgs[0];
113+ * System.out.println(pattform.format(testArgs));
114+ * }
115+ * </pre>
116+ * </blockquote>
117+ * <p>
118+ * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
119+ * For example:
120+ * <blockquote>
121+ * <pre>
122+ * ChoiceFormat fmt = new ChoiceFormat(
123+ * "-1#is negative| 0#is zero or fraction | 1#is one |1.0&lt;is 1+ |2#is two |2&lt;is more than 2.");
124+ * System.out.println("Formatter Pattern : " + fmt.toPattern());
125+ *
126+ * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
127+ * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
128+ * System.out.println("Format with 0 : " + fmt.format(0));
129+ * System.out.println("Format with 0.9 : " + fmt.format(0.9));
130+ * System.out.println("Format with 1.0 : " + fmt.format(1));
131+ * System.out.println("Format with 1.5 : " + fmt.format(1.5));
132+ * System.out.println("Format with 2 : " + fmt.format(2));
133+ * System.out.println("Format with 2.1 : " + fmt.format(2.1));
134+ * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
135+ * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
136+ * </pre>
137+ * </blockquote>
138+ * And the output result would be like the following:
139+ * <blockquote>
140+ * <pre>
141+ * Format with -INF : is negative
142+ * Format with -1.0 : is negative
143+ * Format with 0 : is zero or fraction
144+ * Format with 0.9 : is zero or fraction
145+ * Format with 1.0 : is one
146+ * Format with 1.5 : is 1+
147+ * Format with 2 : is two
148+ * Format with 2.1 : is more than 2.
149+ * Format with NaN : is negative
150+ * Format with +INF : is more than 2.
151+ * </pre>
152+ * </blockquote>
153+ *
154+ * <h4><a name="synchronization">Synchronization</a></h4>
155+ *
156+ * <p>
157+ * Choice formats are not synchronized.
158+ * It is recommended to create separate format instances for each thread.
159+ * If multiple threads access a format concurrently, it must be synchronized
160+ * externally.
161+ *
162+ *
163+ * @see DecimalFormat
164+ * @see MessageFormat
165+ * @author Mark Davis
166+ */
167+public class ChoiceFormat extends NumberFormat {
168+
169+ // Proclaim serial compatibility with 1.1 FCS
170+ private static final long serialVersionUID = 1795184449645032964L;
171+
172+ /**
173+ * Sets the pattern.
174+ * @param newPattern See the class description.
175+ */
176+ public void applyPattern(String newPattern) {
177+ StringBuffer[] segments = new StringBuffer[2];
178+ for (int i = 0; i < segments.length; ++i) {
179+ segments[i] = new StringBuffer();
180+ }
181+ double[] newChoiceLimits = new double[30];
182+ String[] newChoiceFormats = new String[30];
183+ int count = 0;
184+ int part = 0;
185+ double startValue = 0;
186+ double oldStartValue = Double.NaN;
187+ boolean inQuote = false;
188+ for (int i = 0; i < newPattern.length(); ++i) {
189+ char ch = newPattern.charAt(i);
190+ if (ch=='\'') {
191+ // Check for "''" indicating a literal quote
192+ if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
193+ segments[part].append(ch);
194+ ++i;
195+ } else {
196+ inQuote = !inQuote;
197+ }
198+ } else if (inQuote) {
199+ segments[part].append(ch);
200+ } else if (ch == '<' || ch == '#' || ch == '\u2264') {
201+ if (segments[0].length() == 0) {
202+ throw new IllegalArgumentException();
203+ }
204+ try {
205+ String tempBuffer = segments[0].toString();
206+ if (tempBuffer.equals("\u221E")) {
207+ startValue = Double.POSITIVE_INFINITY;
208+ } else if (tempBuffer.equals("-\u221E")) {
209+ startValue = Double.NEGATIVE_INFINITY;
210+ } else {
211+ startValue = Double.valueOf(segments[0].toString()).doubleValue();
212+ }
213+ } catch (Exception e) {
214+ throw new IllegalArgumentException();
215+ }
216+ if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
217+ startValue != Double.NEGATIVE_INFINITY) {
218+ startValue = nextDouble(startValue);
219+ }
220+ if (startValue <= oldStartValue) {
221+ throw new IllegalArgumentException();
222+ }
223+ segments[0].setLength(0);
224+ part = 1;
225+ } else if (ch == '|') {
226+ if (count == newChoiceLimits.length) {
227+ newChoiceLimits = doubleArraySize(newChoiceLimits);
228+ newChoiceFormats = doubleArraySize(newChoiceFormats);
229+ }
230+ newChoiceLimits[count] = startValue;
231+ newChoiceFormats[count] = segments[1].toString();
232+ ++count;
233+ oldStartValue = startValue;
234+ segments[1].setLength(0);
235+ part = 0;
236+ } else {
237+ segments[part].append(ch);
238+ }
239+ }
240+ // clean up last one
241+ if (part == 1) {
242+ if (count == newChoiceLimits.length) {
243+ newChoiceLimits = doubleArraySize(newChoiceLimits);
244+ newChoiceFormats = doubleArraySize(newChoiceFormats);
245+ }
246+ newChoiceLimits[count] = startValue;
247+ newChoiceFormats[count] = segments[1].toString();
248+ ++count;
249+ }
250+ choiceLimits = new double[count];
251+ System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
252+ choiceFormats = new String[count];
253+ System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
254+ }
255+
256+ /**
257+ * Gets the pattern.
258+ */
259+ public String toPattern() {
260+ StringBuffer result = new StringBuffer();
261+ for (int i = 0; i < choiceLimits.length; ++i) {
262+ if (i != 0) {
263+ result.append('|');
264+ }
265+ // choose based upon which has less precision
266+ // approximate that by choosing the closest one to an integer.
267+ // could do better, but it's not worth it.
268+ double less = previousDouble(choiceLimits[i]);
269+ double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
270+ double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
271+
272+ if (tryLessOrEqual < tryLess) {
273+ result.append(""+choiceLimits[i]);
274+ result.append('#');
275+ } else {
276+ if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
277+ result.append("\u221E");
278+ } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
279+ result.append("-\u221E");
280+ } else {
281+ result.append(""+less);
282+ }
283+ result.append('<');
284+ }
285+ // Append choiceFormats[i], using quotes if there are special characters.
286+ // Single quotes themselves must be escaped in either case.
287+ String text = choiceFormats[i];
288+ boolean needQuote = text.indexOf('<') >= 0
289+ || text.indexOf('#') >= 0
290+ || text.indexOf('\u2264') >= 0
291+ || text.indexOf('|') >= 0;
292+ if (needQuote) result.append('\'');
293+ if (text.indexOf('\'') < 0) result.append(text);
294+ else {
295+ for (int j=0; j<text.length(); ++j) {
296+ char c = text.charAt(j);
297+ result.append(c);
298+ if (c == '\'') result.append(c);
299+ }
300+ }
301+ if (needQuote) result.append('\'');
302+ }
303+ return result.toString();
304+ }
305+
306+ /**
307+ * Constructs with limits and corresponding formats based on the pattern.
308+ * @see #applyPattern
309+ */
310+ public ChoiceFormat(String newPattern) {
311+ applyPattern(newPattern);
312+ }
313+
314+ /**
315+ * Constructs with the limits and the corresponding formats.
316+ * @see #setChoices
317+ */
318+ public ChoiceFormat(double[] limits, String[] formats) {
319+ setChoices(limits, formats);
320+ }
321+
322+ /**
323+ * Set the choices to be used in formatting.
324+ * @param limits contains the top value that you want
325+ * parsed with that format,and should be in ascending sorted order. When
326+ * formatting X, the choice will be the i, where
327+ * limit[i] &lt;= X &lt; limit[i+1].
328+ * If the limit array is not in ascending order, the results of formatting
329+ * will be incorrect.
330+ * @param formats are the formats you want to use for each limit.
331+ * They can be either Format objects or Strings.
332+ * When formatting with object Y,
333+ * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
334+ * is called. Otherwise Y.toString() is called.
335+ */
336+ public void setChoices(double[] limits, String formats[]) {
337+ if (limits.length != formats.length) {
338+ throw new IllegalArgumentException(
339+ "Array and limit arrays must be of the same length.");
340+ }
341+ choiceLimits = limits;
342+ choiceFormats = formats;
343+ }
344+
345+ /**
346+ * Get the limits passed in the constructor.
347+ * @return the limits.
348+ */
349+ public double[] getLimits() {
350+ return choiceLimits;
351+ }
352+
353+ /**
354+ * Get the formats passed in the constructor.
355+ * @return the formats.
356+ */
357+ public Object[] getFormats() {
358+ return choiceFormats;
359+ }
360+
361+ // Overrides
362+
363+ /**
364+ * Specialization of format. This method really calls
365+ * <code>format(double, StringBuffer, FieldPosition)</code>
366+ * thus the range of longs that are supported is only equal to
367+ * the range that can be stored by double. This will never be
368+ * a practical limitation.
369+ */
370+ public StringBuffer format(long number, StringBuffer toAppendTo,
371+ FieldPosition status) {
372+ return format((double)number, toAppendTo, status);
373+ }
374+
375+ /**
376+ * Returns pattern with formatted double.
377+ * @param number number to be formatted & substituted.
378+ * @param toAppendTo where text is appended.
379+ * @param status ignore no useful status is returned.
380+ */
381+ public StringBuffer format(double number, StringBuffer toAppendTo,
382+ FieldPosition status) {
383+ // find the number
384+ int i;
385+ for (i = 0; i < choiceLimits.length; ++i) {
386+ if (!(number >= choiceLimits[i])) {
387+ // same as number < choiceLimits, except catchs NaN
388+ break;
389+ }
390+ }
391+ --i;
392+ if (i < 0) i = 0;
393+ // return either a formatted number, or a string
394+ return toAppendTo.append(choiceFormats[i]);
395+ }
396+
397+ /**
398+ * Parses a Number from the input text.
399+ * @param text the source text.
400+ * @param status an input-output parameter. On input, the
401+ * status.index field indicates the first character of the
402+ * source text that should be parsed. On exit, if no error
403+ * occured, status.index is set to the first unparsed character
404+ * in the source text. On exit, if an error did occur,
405+ * status.index is unchanged and status.errorIndex is set to the
406+ * first index of the character that caused the parse to fail.
407+ * @return A Number representing the value of the number parsed.
408+ */
409+ public Number parse(String text, ParsePosition status) {
410+ // find the best number (defined as the one with the longest parse)
411+ int start = status.index;
412+ int furthest = start;
413+ double bestNumber = Double.NaN;
414+ double tempNumber = 0.0;
415+ for (int i = 0; i < choiceFormats.length; ++i) {
416+ String tempString = choiceFormats[i];
417+ if (text.regionMatches(start, tempString, 0, tempString.length())) {
418+ status.index = start + tempString.length();
419+ tempNumber = choiceLimits[i];
420+ if (status.index > furthest) {
421+ furthest = status.index;
422+ bestNumber = tempNumber;
423+ if (furthest == text.length()) break;
424+ }
425+ }
426+ }
427+ status.index = furthest;
428+ if (status.index == start) {
429+ status.errorIndex = furthest;
430+ }
431+ return new Double(bestNumber);
432+ }
433+
434+ /**
435+ * Finds the least double greater than d.
436+ * If NaN, returns same value.
437+ * <p>Used to make half-open intervals.
438+ * @see #previousDouble
439+ */
440+ public static final double nextDouble (double d) {
441+ return nextDouble(d,true);
442+ }
443+
444+ /**
445+ * Finds the greatest double less than d.
446+ * If NaN, returns same value.
447+ * @see #nextDouble
448+ */
449+ public static final double previousDouble (double d) {
450+ return nextDouble(d,false);
451+ }
452+
453+ /**
454+ * Overrides Cloneable
455+ */
456+ public Object clone()
457+ {
458+ ChoiceFormat other = (ChoiceFormat) super.clone();
459+ // for primitives or immutables, shallow clone is enough
460+ other.choiceLimits = (double[]) choiceLimits.clone();
461+ other.choiceFormats = (String[]) choiceFormats.clone();
462+ return other;
463+ }
464+
465+ /**
466+ * Generates a hash code for the message format object.
467+ */
468+ public int hashCode() {
469+ int result = choiceLimits.length;
470+ if (choiceFormats.length > 0) {
471+ // enough for reasonable distribution
472+ result ^= choiceFormats[choiceFormats.length-1].hashCode();
473+ }
474+ return result;
475+ }
476+
477+ /**
478+ * Equality comparision between two
479+ */
480+ public boolean equals(Object obj) {
481+ if (obj == null) return false;
482+ if (this == obj) // quick check
483+ return true;
484+ if (getClass() != obj.getClass())
485+ return false;
486+ ChoiceFormat other = (ChoiceFormat) obj;
487+ return (Arrays.equals(choiceLimits, other.choiceLimits)
488+ && Arrays.equals(choiceFormats, other.choiceFormats));
489+ }
490+
491+ /**
492+ * After reading an object from the input stream, do a simple verification
493+ * to maintain class invariants.
494+ * @throws InvalidObjectException if the objects read from the stream is invalid.
495+ */
496+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
497+ in.defaultReadObject();
498+ if (choiceLimits.length != choiceFormats.length) {
499+ throw new InvalidObjectException(
500+ "limits and format arrays of different length.");
501+ }
502+ }
503+
504+ // ===============privates===========================
505+
506+ /**
507+ * A list of lower bounds for the choices. The formatter will return
508+ * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
509+ * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
510+ * @serial
511+ */
512+ private double[] choiceLimits;
513+
514+ /**
515+ * A list of choice strings. The formatter will return
516+ * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
517+ * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
518+ * @serial
519+ */
520+ private String[] choiceFormats;
521+
522+ /*
523+ static final long SIGN = 0x8000000000000000L;
524+ static final long EXPONENT = 0x7FF0000000000000L;
525+ static final long SIGNIFICAND = 0x000FFFFFFFFFFFFFL;
526+
527+ private static double nextDouble (double d, boolean positive) {
528+ if (Double.isNaN(d) || Double.isInfinite(d)) {
529+ return d;
530+ }
531+ long bits = Double.doubleToLongBits(d);
532+ long significand = bits & SIGNIFICAND;
533+ if (bits < 0) {
534+ significand |= (SIGN | EXPONENT);
535+ }
536+ long exponent = bits & EXPONENT;
537+ if (positive) {
538+ significand += 1;
539+ // FIXME fix overflow & underflow
540+ } else {
541+ significand -= 1;
542+ // FIXME fix overflow & underflow
543+ }
544+ bits = exponent | (significand & ~EXPONENT);
545+ return Double.longBitsToDouble(bits);
546+ }
547+ */
548+
549+ static final long SIGN = 0x8000000000000000L;
550+ static final long EXPONENT = 0x7FF0000000000000L;
551+ static final long POSITIVEINFINITY = 0x7FF0000000000000L;
552+
553+ /**
554+ * Finds the least double greater than d (if positive == true),
555+ * or the greatest double less than d (if positive == false).
556+ * If NaN, returns same value.
557+ *
558+ * Does not affect floating-point flags,
559+ * provided these member functions do not:
560+ * Double.longBitsToDouble(long)
561+ * Double.doubleToLongBits(double)
562+ * Double.isNaN(double)
563+ */
564+ public static double nextDouble (double d, boolean positive) {
565+
566+ /* filter out NaN's */
567+ if (Double.isNaN(d)) {
568+ return d;
569+ }
570+
571+ /* zero's are also a special case */
572+ if (d == 0.0) {
573+ double smallestPositiveDouble = Double.longBitsToDouble(1L);
574+ if (positive) {
575+ return smallestPositiveDouble;
576+ } else {
577+ return -smallestPositiveDouble;
578+ }
579+ }
580+
581+ /* if entering here, d is a nonzero value */
582+
583+ /* hold all bits in a long for later use */
584+ long bits = Double.doubleToLongBits(d);
585+
586+ /* strip off the sign bit */
587+ long magnitude = bits & ~SIGN;
588+
589+ /* if next double away from zero, increase magnitude */
590+ if ((bits > 0) == positive) {
591+ if (magnitude != POSITIVEINFINITY) {
592+ magnitude += 1;
593+ }
594+ }
595+ /* else decrease magnitude */
596+ else {
597+ magnitude -= 1;
598+ }
599+
600+ /* restore sign bit and return */
601+ long signbit = bits & SIGN;
602+ return Double.longBitsToDouble (magnitude | signbit);
603+ }
604+
605+ private static double[] doubleArraySize(double[] array) {
606+ int oldSize = array.length;
607+ double[] newArray = new double[oldSize * 2];
608+ System.arraycopy(array, 0, newArray, 0, oldSize);
609+ return newArray;
610+ }
611+
612+ private String[] doubleArraySize(String[] array) {
613+ int oldSize = array.length;
614+ String[] newArray = new String[oldSize * 2];
615+ System.arraycopy(array, 0, newArray, 0, oldSize);
616+ return newArray;
617+ }
618+
619+}
java/pkg/java/text/CollationElementIterator.class+0−0

Binary file not shown.

java/pkg/java/text/CollationElementIterator.java+777−0
@@ -0,0 +1,777 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.lang.Character;
42+import java.util.Vector;
43+import sun.text.CollatorUtilities;
44+import sun.text.normalizer.NormalizerBase;
45+
46+/**
47+ * The <code>CollationElementIterator</code> class is used as an iterator
48+ * to walk through each character of an international string. Use the iterator
49+ * to return the ordering priority of the positioned character. The ordering
50+ * priority of a character, which we refer to as a key, defines how a character
51+ * is collated in the given collation object.
52+ *
53+ * <p>
54+ * For example, consider the following in Spanish:
55+ * <blockquote>
56+ * <pre>
57+ * "ca" -> the first key is key('c') and second key is key('a').
58+ * "cha" -> the first key is key('ch') and second key is key('a').
59+ * </pre>
60+ * </blockquote>
61+ * And in German,
62+ * <blockquote>
63+ * <pre>
64+ * "\u00e4b"-> the first key is key('a'), the second key is key('e'), and
65+ * the third key is key('b').
66+ * </pre>
67+ * </blockquote>
68+ * The key of a character is an integer composed of primary order(short),
69+ * secondary order(byte), and tertiary order(byte). Java strictly defines
70+ * the size and signedness of its primitive data types. Therefore, the static
71+ * functions <code>primaryOrder</code>, <code>secondaryOrder</code>, and
72+ * <code>tertiaryOrder</code> return <code>int</code>, <code>short</code>,
73+ * and <code>short</code> respectively to ensure the correctness of the key
74+ * value.
75+ *
76+ * <p>
77+ * Example of the iterator usage,
78+ * <blockquote>
79+ * <pre>
80+ *
81+ * String testString = "This is a test";
82+ * Collator col = Collator.getInstance();
83+ * if (col instanceof RuleBasedCollator) {
84+ * RuleBasedCollator ruleBasedCollator = (RuleBasedCollator)col;
85+ * CollationElementIterator collationElementIterator = ruleBasedCollator.getCollationElementIterator(testString);
86+ * int primaryOrder = CollationElementIterator.primaryOrder(collationElementIterator.next());
87+ * :
88+ * }
89+ * </pre>
90+ * </blockquote>
91+ *
92+ * <p>
93+ * <code>CollationElementIterator.next</code> returns the collation order
94+ * of the next character. A collation order consists of primary order,
95+ * secondary order and tertiary order. The data type of the collation
96+ * order is <strong>int</strong>. The first 16 bits of a collation order
97+ * is its primary order; the next 8 bits is the secondary order and the
98+ * last 8 bits is the tertiary order.
99+ *
100+ * <p><b>Note:</b> <code>CollationElementIterator</code> is a part of
101+ * <code>RuleBasedCollator</code> implementation. It is only usable
102+ * with <code>RuleBasedCollator</code> instances.
103+ *
104+ * @see Collator
105+ * @see RuleBasedCollator
106+ * @author Helena Shih, Laura Werner, Richard Gillam
107+ */
108+public final class CollationElementIterator
109+{
110+ /**
111+ * Null order which indicates the end of string is reached by the
112+ * cursor.
113+ */
114+ public final static int NULLORDER = 0xffffffff;
115+
116+ /**
117+ * CollationElementIterator constructor. This takes the source string and
118+ * the collation object. The cursor will walk thru the source string based
119+ * on the predefined collation rules. If the source string is empty,
120+ * NULLORDER will be returned on the calls to next().
121+ * @param sourceText the source string.
122+ * @param order the collation object.
123+ */
124+ CollationElementIterator(String sourceText, RuleBasedCollator owner) {
125+ this.owner = owner;
126+ ordering = owner.getTables();
127+ if ( sourceText.length() != 0 ) {
128+ NormalizerBase.Mode mode =
129+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
130+ text = new NormalizerBase(sourceText, mode);
131+ }
132+ }
133+
134+ /**
135+ * CollationElementIterator constructor. This takes the source string and
136+ * the collation object. The cursor will walk thru the source string based
137+ * on the predefined collation rules. If the source string is empty,
138+ * NULLORDER will be returned on the calls to next().
139+ * @param sourceText the source string.
140+ * @param order the collation object.
141+ */
142+ CollationElementIterator(CharacterIterator sourceText, RuleBasedCollator owner) {
143+ this.owner = owner;
144+ ordering = owner.getTables();
145+ NormalizerBase.Mode mode =
146+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
147+ text = new NormalizerBase(sourceText, mode);
148+ }
149+
150+ /**
151+ * Resets the cursor to the beginning of the string. The next call
152+ * to next() will return the first collation element in the string.
153+ */
154+ public void reset()
155+ {
156+ if (text != null) {
157+ text.reset();
158+ NormalizerBase.Mode mode =
159+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
160+ text.setMode(mode);
161+ }
162+ buffer = null;
163+ expIndex = 0;
164+ swapOrder = 0;
165+ }
166+
167+ /**
168+ * Get the next collation element in the string. <p>This iterator iterates
169+ * over a sequence of collation elements that were built from the string.
170+ * Because there isn't necessarily a one-to-one mapping from characters to
171+ * collation elements, this doesn't mean the same thing as "return the
172+ * collation element [or ordering priority] of the next character in the
173+ * string".</p>
174+ * <p>This function returns the collation element that the iterator is currently
175+ * pointing to and then updates the internal pointer to point to the next element.
176+ * previous() updates the pointer first and then returns the element. This
177+ * means that when you change direction while iterating (i.e., call next() and
178+ * then call previous(), or call previous() and then call next()), you'll get
179+ * back the same element twice.</p>
180+ */
181+ public int next()
182+ {
183+ if (text == null) {
184+ return NULLORDER;
185+ }
186+ NormalizerBase.Mode textMode = text.getMode();
187+ // convert the owner's mode to something the Normalizer understands
188+ NormalizerBase.Mode ownerMode =
189+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
190+ if (textMode != ownerMode) {
191+ text.setMode(ownerMode);
192+ }
193+
194+ // if buffer contains any decomposed char values
195+ // return their strength orders before continuing in
196+ // the Normalizer's CharacterIterator.
197+ if (buffer != null) {
198+ if (expIndex < buffer.length) {
199+ return strengthOrder(buffer[expIndex++]);
200+ } else {
201+ buffer = null;
202+ expIndex = 0;
203+ }
204+ } else if (swapOrder != 0) {
205+ if (Character.isSupplementaryCodePoint(swapOrder)) {
206+ char[] chars = Character.toChars(swapOrder);
207+ swapOrder = chars[1];
208+ return chars[0] << 16;
209+ }
210+ int order = swapOrder << 16;
211+ swapOrder = 0;
212+ return order;
213+ }
214+ int ch = text.next();
215+
216+ // are we at the end of Normalizer's text?
217+ if (ch == NormalizerBase.DONE) {
218+ return NULLORDER;
219+ }
220+
221+ int value = ordering.getUnicodeOrder(ch);
222+ if (value == RuleBasedCollator.UNMAPPED) {
223+ swapOrder = ch;
224+ return UNMAPPEDCHARVALUE;
225+ }
226+ else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
227+ value = nextContractChar(ch);
228+ }
229+ if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
230+ buffer = ordering.getExpandValueList(value);
231+ expIndex = 0;
232+ value = buffer[expIndex++];
233+ }
234+
235+ if (ordering.isSEAsianSwapping()) {
236+ int consonant;
237+ if (isThaiPreVowel(ch)) {
238+ consonant = text.next();
239+ if (isThaiBaseConsonant(consonant)) {
240+ buffer = makeReorderedBuffer(consonant, value, buffer, true);
241+ value = buffer[0];
242+ expIndex = 1;
243+ } else if (consonant != NormalizerBase.DONE) {
244+ text.previous();
245+ }
246+ }
247+ if (isLaoPreVowel(ch)) {
248+ consonant = text.next();
249+ if (isLaoBaseConsonant(consonant)) {
250+ buffer = makeReorderedBuffer(consonant, value, buffer, true);
251+ value = buffer[0];
252+ expIndex = 1;
253+ } else if (consonant != NormalizerBase.DONE) {
254+ text.previous();
255+ }
256+ }
257+ }
258+
259+ return strengthOrder(value);
260+ }
261+
262+ /**
263+ * Get the previous collation element in the string. <p>This iterator iterates
264+ * over a sequence of collation elements that were built from the string.
265+ * Because there isn't necessarily a one-to-one mapping from characters to
266+ * collation elements, this doesn't mean the same thing as "return the
267+ * collation element [or ordering priority] of the previous character in the
268+ * string".</p>
269+ * <p>This function updates the iterator's internal pointer to point to the
270+ * collation element preceding the one it's currently pointing to and then
271+ * returns that element, while next() returns the current element and then
272+ * updates the pointer. This means that when you change direction while
273+ * iterating (i.e., call next() and then call previous(), or call previous()
274+ * and then call next()), you'll get back the same element twice.</p>
275+ * @since 1.2
276+ */
277+ public int previous()
278+ {
279+ if (text == null) {
280+ return NULLORDER;
281+ }
282+ NormalizerBase.Mode textMode = text.getMode();
283+ // convert the owner's mode to something the Normalizer understands
284+ NormalizerBase.Mode ownerMode =
285+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
286+ if (textMode != ownerMode) {
287+ text.setMode(ownerMode);
288+ }
289+ if (buffer != null) {
290+ if (expIndex > 0) {
291+ return strengthOrder(buffer[--expIndex]);
292+ } else {
293+ buffer = null;
294+ expIndex = 0;
295+ }
296+ } else if (swapOrder != 0) {
297+ if (Character.isSupplementaryCodePoint(swapOrder)) {
298+ char[] chars = Character.toChars(swapOrder);
299+ swapOrder = chars[1];
300+ return chars[0] << 16;
301+ }
302+ int order = swapOrder << 16;
303+ swapOrder = 0;
304+ return order;
305+ }
306+ int ch = text.previous();
307+ if (ch == NormalizerBase.DONE) {
308+ return NULLORDER;
309+ }
310+
311+ int value = ordering.getUnicodeOrder(ch);
312+
313+ if (value == RuleBasedCollator.UNMAPPED) {
314+ swapOrder = UNMAPPEDCHARVALUE;
315+ return ch;
316+ } else if (value >= RuleBasedCollator.CONTRACTCHARINDEX) {
317+ value = prevContractChar(ch);
318+ }
319+ if (value >= RuleBasedCollator.EXPANDCHARINDEX) {
320+ buffer = ordering.getExpandValueList(value);
321+ expIndex = buffer.length;
322+ value = buffer[--expIndex];
323+ }
324+
325+ if (ordering.isSEAsianSwapping()) {
326+ int vowel;
327+ if (isThaiBaseConsonant(ch)) {
328+ vowel = text.previous();
329+ if (isThaiPreVowel(vowel)) {
330+ buffer = makeReorderedBuffer(vowel, value, buffer, false);
331+ expIndex = buffer.length - 1;
332+ value = buffer[expIndex];
333+ } else {
334+ text.next();
335+ }
336+ }
337+ if (isLaoBaseConsonant(ch)) {
338+ vowel = text.previous();
339+ if (isLaoPreVowel(vowel)) {
340+ buffer = makeReorderedBuffer(vowel, value, buffer, false);
341+ expIndex = buffer.length - 1;
342+ value = buffer[expIndex];
343+ } else {
344+ text.next();
345+ }
346+ }
347+ }
348+
349+ return strengthOrder(value);
350+ }
351+
352+ /**
353+ * Return the primary component of a collation element.
354+ * @param order the collation element
355+ * @return the element's primary component
356+ */
357+ public final static int primaryOrder(int order)
358+ {
359+ order &= RBCollationTables.PRIMARYORDERMASK;
360+ return (order >>> RBCollationTables.PRIMARYORDERSHIFT);
361+ }
362+ /**
363+ * Return the secondary component of a collation element.
364+ * @param order the collation element
365+ * @return the element's secondary component
366+ */
367+ public final static short secondaryOrder(int order)
368+ {
369+ order = order & RBCollationTables.SECONDARYORDERMASK;
370+ return ((short)(order >> RBCollationTables.SECONDARYORDERSHIFT));
371+ }
372+ /**
373+ * Return the tertiary component of a collation element.
374+ * @param order the collation element
375+ * @return the element's tertiary component
376+ */
377+ public final static short tertiaryOrder(int order)
378+ {
379+ return ((short)(order &= RBCollationTables.TERTIARYORDERMASK));
380+ }
381+
382+ /**
383+ * Get the comparison order in the desired strength. Ignore the other
384+ * differences.
385+ * @param order The order value
386+ */
387+ final int strengthOrder(int order)
388+ {
389+ int s = owner.getStrength();
390+ if (s == Collator.PRIMARY)
391+ {
392+ order &= RBCollationTables.PRIMARYDIFFERENCEONLY;
393+ } else if (s == Collator.SECONDARY)
394+ {
395+ order &= RBCollationTables.SECONDARYDIFFERENCEONLY;
396+ }
397+ return order;
398+ }
399+
400+ /**
401+ * Sets the iterator to point to the collation element corresponding to
402+ * the specified character (the parameter is a CHARACTER offset in the
403+ * original string, not an offset into its corresponding sequence of
404+ * collation elements). The value returned by the next call to next()
405+ * will be the collation element corresponding to the specified position
406+ * in the text. If that position is in the middle of a contracting
407+ * character sequence, the result of the next call to next() is the
408+ * collation element for that sequence. This means that getOffset()
409+ * is not guaranteed to return the same value as was passed to a preceding
410+ * call to setOffset().
411+ *
412+ * @param newOffset The new character offset into the original text.
413+ * @since 1.2
414+ */
415+ public void setOffset(int newOffset)
416+ {
417+ if (text != null) {
418+ if (newOffset < text.getBeginIndex()
419+ || newOffset >= text.getEndIndex()) {
420+ text.setIndexOnly(newOffset);
421+ } else {
422+ int c = text.setIndex(newOffset);
423+
424+ // if the desired character isn't used in a contracting character
425+ // sequence, bypass all the backing-up logic-- we're sitting on
426+ // the right character already
427+ if (ordering.usedInContractSeq(c)) {
428+ // walk backwards through the string until we see a character
429+ // that DOESN'T participate in a contracting character sequence
430+ while (ordering.usedInContractSeq(c)) {
431+ c = text.previous();
432+ }
433+ // now walk forward using this object's next() method until
434+ // we pass the starting point and set our current position
435+ // to the beginning of the last "character" before or at
436+ // our starting position
437+ int last = text.getIndex();
438+ while (text.getIndex() <= newOffset) {
439+ last = text.getIndex();
440+ next();
441+ }
442+ text.setIndexOnly(last);
443+ // we don't need this, since last is the last index
444+ // that is the starting of the contraction which encompass
445+ // newOffset
446+ // text.previous();
447+ }
448+ }
449+ }
450+ buffer = null;
451+ expIndex = 0;
452+ swapOrder = 0;
453+ }
454+
455+ /**
456+ * Returns the character offset in the original text corresponding to the next
457+ * collation element. (That is, getOffset() returns the position in the text
458+ * corresponding to the collation element that will be returned by the next
459+ * call to next().) This value will always be the index of the FIRST character
460+ * corresponding to the collation element (a contracting character sequence is
461+ * when two or more characters all correspond to the same collation element).
462+ * This means if you do setOffset(x) followed immediately by getOffset(), getOffset()
463+ * won't necessarily return x.
464+ *
465+ * @return The character offset in the original text corresponding to the collation
466+ * element that will be returned by the next call to next().
467+ * @since 1.2
468+ */
469+ public int getOffset()
470+ {
471+ return (text != null) ? text.getIndex() : 0;
472+ }
473+
474+
475+ /**
476+ * Return the maximum length of any expansion sequences that end
477+ * with the specified comparison order.
478+ * @param order a collation order returned by previous or next.
479+ * @return the maximum length of any expansion sequences ending
480+ * with the specified order.
481+ * @since 1.2
482+ */
483+ public int getMaxExpansion(int order)
484+ {
485+ return ordering.getMaxExpansion(order);
486+ }
487+
488+ /**
489+ * Set a new string over which to iterate.
490+ *
491+ * @param source the new source text
492+ * @since 1.2
493+ */
494+ public void setText(String source)
495+ {
496+ buffer = null;
497+ swapOrder = 0;
498+ expIndex = 0;
499+ NormalizerBase.Mode mode =
500+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
501+ if (text == null) {
502+ text = new NormalizerBase(source, mode);
503+ } else {
504+ text.setMode(mode);
505+ text.setText(source);
506+ }
507+ }
508+
509+ /**
510+ * Set a new string over which to iterate.
511+ *
512+ * @param source the new source text.
513+ * @since 1.2
514+ */
515+ public void setText(CharacterIterator source)
516+ {
517+ buffer = null;
518+ swapOrder = 0;
519+ expIndex = 0;
520+ NormalizerBase.Mode mode =
521+ CollatorUtilities.toNormalizerMode(owner.getDecomposition());
522+ if (text == null) {
523+ text = new NormalizerBase(source, mode);
524+ } else {
525+ text.setMode(mode);
526+ text.setText(source);
527+ }
528+ }
529+
530+ //============================================================
531+ // privates
532+ //============================================================
533+
534+ /**
535+ * Determine if a character is a Thai vowel (which sorts after
536+ * its base consonant).
537+ */
538+ private final static boolean isThaiPreVowel(int ch) {
539+ return (ch >= 0x0e40) && (ch <= 0x0e44);
540+ }
541+
542+ /**
543+ * Determine if a character is a Thai base consonant
544+ */
545+ private final static boolean isThaiBaseConsonant(int ch) {
546+ return (ch >= 0x0e01) && (ch <= 0x0e2e);
547+ }
548+
549+ /**
550+ * Determine if a character is a Lao vowel (which sorts after
551+ * its base consonant).
552+ */
553+ private final static boolean isLaoPreVowel(int ch) {
554+ return (ch >= 0x0ec0) && (ch <= 0x0ec4);
555+ }
556+
557+ /**
558+ * Determine if a character is a Lao base consonant
559+ */
560+ private final static boolean isLaoBaseConsonant(int ch) {
561+ return (ch >= 0x0e81) && (ch <= 0x0eae);
562+ }
563+
564+ /**
565+ * This method produces a buffer which contains the collation
566+ * elements for the two characters, with colFirst's values preceding
567+ * another character's. Presumably, the other character precedes colFirst
568+ * in logical order (otherwise you wouldn't need this method would you?).
569+ * The assumption is that the other char's value(s) have already been
570+ * computed. If this char has a single element it is passed to this
571+ * method as lastValue, and lastExpansion is null. If it has an
572+ * expansion it is passed in lastExpansion, and colLastValue is ignored.
573+ */
574+ private int[] makeReorderedBuffer(int colFirst,
575+ int lastValue,
576+ int[] lastExpansion,
577+ boolean forward) {
578+
579+ int[] result;
580+
581+ int firstValue = ordering.getUnicodeOrder(colFirst);
582+ if (firstValue >= RuleBasedCollator.CONTRACTCHARINDEX) {
583+ firstValue = forward? nextContractChar(colFirst) : prevContractChar(colFirst);
584+ }
585+
586+ int[] firstExpansion = null;
587+ if (firstValue >= RuleBasedCollator.EXPANDCHARINDEX) {
588+ firstExpansion = ordering.getExpandValueList(firstValue);
589+ }
590+
591+ if (!forward) {
592+ int temp1 = firstValue;
593+ firstValue = lastValue;
594+ lastValue = temp1;
595+ int[] temp2 = firstExpansion;
596+ firstExpansion = lastExpansion;
597+ lastExpansion = temp2;
598+ }
599+
600+ if (firstExpansion == null && lastExpansion == null) {
601+ result = new int [2];
602+ result[0] = firstValue;
603+ result[1] = lastValue;
604+ }
605+ else {
606+ int firstLength = firstExpansion==null? 1 : firstExpansion.length;
607+ int lastLength = lastExpansion==null? 1 : lastExpansion.length;
608+ result = new int[firstLength + lastLength];
609+
610+ if (firstExpansion == null) {
611+ result[0] = firstValue;
612+ }
613+ else {
614+ System.arraycopy(firstExpansion, 0, result, 0, firstLength);
615+ }
616+
617+ if (lastExpansion == null) {
618+ result[firstLength] = lastValue;
619+ }
620+ else {
621+ System.arraycopy(lastExpansion, 0, result, firstLength, lastLength);
622+ }
623+ }
624+
625+ return result;
626+ }
627+
628+ /**
629+ * Check if a comparison order is ignorable.
630+ * @return true if a character is ignorable, false otherwise.
631+ */
632+ final static boolean isIgnorable(int order)
633+ {
634+ return ((primaryOrder(order) == 0) ? true : false);
635+ }
636+
637+ /**
638+ * Get the ordering priority of the next contracting character in the
639+ * string.
640+ * @param ch the starting character of a contracting character token
641+ * @return the next contracting character's ordering. Returns NULLORDER
642+ * if the end of string is reached.
643+ */
644+ private int nextContractChar(int ch)
645+ {
646+ // First get the ordering of this single character,
647+ // which is always the first element in the list
648+ Vector list = ordering.getContractValues(ch);
649+ EntryPair pair = (EntryPair)list.firstElement();
650+ int order = pair.value;
651+
652+ // find out the length of the longest contracting character sequence in the list.
653+ // There's logic in the builder code to make sure the longest sequence is always
654+ // the last.
655+ pair = (EntryPair)list.lastElement();
656+ int maxLength = pair.entryName.length();
657+
658+ // (the Normalizer is cloned here so that the seeking we do in the next loop
659+ // won't affect our real position in the text)
660+ NormalizerBase tempText = (NormalizerBase)text.clone();
661+
662+ // extract the next maxLength characters in the string (we have to do this using the
663+ // Normalizer to ensure that our offsets correspond to those the rest of the
664+ // iterator is using) and store it in "fragment".
665+ tempText.previous();
666+ key.setLength(0);
667+ int c = tempText.next();
668+ while (maxLength > 0 && c != NormalizerBase.DONE) {
669+ if (Character.isSupplementaryCodePoint(c)) {
670+ key.append(Character.toChars(c));
671+ maxLength -= 2;
672+ } else {
673+ key.append((char)c);
674+ --maxLength;
675+ }
676+ c = tempText.next();
677+ }
678+ String fragment = key.toString();
679+ // now that we have that fragment, iterate through this list looking for the
680+ // longest sequence that matches the characters in the actual text. (maxLength
681+ // is used here to keep track of the length of the longest sequence)
682+ // Upon exit from this loop, maxLength will contain the length of the matching
683+ // sequence and order will contain the collation-element value corresponding
684+ // to this sequence
685+ maxLength = 1;
686+ for (int i = list.size() - 1; i > 0; i--) {
687+ pair = (EntryPair)list.elementAt(i);
688+ if (!pair.fwd)
689+ continue;
690+
691+ if (fragment.startsWith(pair.entryName) && pair.entryName.length()
692+ > maxLength) {
693+ maxLength = pair.entryName.length();
694+ order = pair.value;
695+ }
696+ }
697+
698+ // seek our current iteration position to the end of the matching sequence
699+ // and return the appropriate collation-element value (if there was no matching
700+ // sequence, we're already seeked to the right position and order already contains
701+ // the correct collation-element value for the single character)
702+ while (maxLength > 1) {
703+ c = text.next();
704+ maxLength -= Character.charCount(c);
705+ }
706+ return order;
707+ }
708+
709+ /**
710+ * Get the ordering priority of the previous contracting character in the
711+ * string.
712+ * @param ch the starting character of a contracting character token
713+ * @return the next contracting character's ordering. Returns NULLORDER
714+ * if the end of string is reached.
715+ */
716+ private int prevContractChar(int ch)
717+ {
718+ // This function is identical to nextContractChar(), except that we've
719+ // switched things so that the next() and previous() calls on the Normalizer
720+ // are switched and so that we skip entry pairs with the fwd flag turned on
721+ // rather than off. Notice that we still use append() and startsWith() when
722+ // working on the fragment. This is because the entry pairs that are used
723+ // in reverse iteration have their names reversed already.
724+ Vector list = ordering.getContractValues(ch);
725+ EntryPair pair = (EntryPair)list.firstElement();
726+ int order = pair.value;
727+
728+ pair = (EntryPair)list.lastElement();
729+ int maxLength = pair.entryName.length();
730+
731+ NormalizerBase tempText = (NormalizerBase)text.clone();
732+
733+ tempText.next();
734+ key.setLength(0);
735+ int c = tempText.previous();
736+ while (maxLength > 0 && c != NormalizerBase.DONE) {
737+ if (Character.isSupplementaryCodePoint(c)) {
738+ key.append(Character.toChars(c));
739+ maxLength -= 2;
740+ } else {
741+ key.append((char)c);
742+ --maxLength;
743+ }
744+ c = tempText.previous();
745+ }
746+ String fragment = key.toString();
747+
748+ maxLength = 1;
749+ for (int i = list.size() - 1; i > 0; i--) {
750+ pair = (EntryPair)list.elementAt(i);
751+ if (pair.fwd)
752+ continue;
753+
754+ if (fragment.startsWith(pair.entryName) && pair.entryName.length()
755+ > maxLength) {
756+ maxLength = pair.entryName.length();
757+ order = pair.value;
758+ }
759+ }
760+
761+ while (maxLength > 1) {
762+ c = text.previous();
763+ maxLength -= Character.charCount(c);
764+ }
765+ return order;
766+ }
767+
768+ final static int UNMAPPEDCHARVALUE = 0x7FFF0000;
769+
770+ private NormalizerBase text = null;
771+ private int[] buffer = null;
772+ private int expIndex = 0;
773+ private StringBuffer key = new StringBuffer(5);
774+ private int swapOrder = 0;
775+ private RBCollationTables ordering;
776+ private RuleBasedCollator owner;
777+}
java/pkg/java/text/CollationKey.class+0−0

Binary file not shown.

java/pkg/java/text/CollationKey.java+145−0
@@ -0,0 +1,145 @@
1+/*
2+ * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+/**
42+ * A <code>CollationKey</code> represents a <code>String</code> under the
43+ * rules of a specific <code>Collator</code> object. Comparing two
44+ * <code>CollationKey</code>s returns the relative order of the
45+ * <code>String</code>s they represent. Using <code>CollationKey</code>s
46+ * to compare <code>String</code>s is generally faster than using
47+ * <code>Collator.compare</code>. Thus, when the <code>String</code>s
48+ * must be compared multiple times, for example when sorting a list
49+ * of <code>String</code>s. It's more efficient to use <code>CollationKey</code>s.
50+ *
51+ * <p>
52+ * You can not create <code>CollationKey</code>s directly. Rather,
53+ * generate them by calling <code>Collator.getCollationKey</code>.
54+ * You can only compare <code>CollationKey</code>s generated from
55+ * the same <code>Collator</code> object.
56+ *
57+ * <p>
58+ * Generating a <code>CollationKey</code> for a <code>String</code>
59+ * involves examining the entire <code>String</code>
60+ * and converting it to series of bits that can be compared bitwise. This
61+ * allows fast comparisons once the keys are generated. The cost of generating
62+ * keys is recouped in faster comparisons when <code>String</code>s need
63+ * to be compared many times. On the other hand, the result of a comparison
64+ * is often determined by the first couple of characters of each <code>String</code>.
65+ * <code>Collator.compare</code> examines only as many characters as it needs which
66+ * allows it to be faster when doing single comparisons.
67+ * <p>
68+ * The following example shows how <code>CollationKey</code>s might be used
69+ * to sort a list of <code>String</code>s.
70+ * <blockquote>
71+ * <pre>
72+ * // Create an array of CollationKeys for the Strings to be sorted.
73+ * Collator myCollator = Collator.getInstance();
74+ * CollationKey[] keys = new CollationKey[3];
75+ * keys[0] = myCollator.getCollationKey("Tom");
76+ * keys[1] = myCollator.getCollationKey("Dick");
77+ * keys[2] = myCollator.getCollationKey("Harry");
78+ * sort( keys );
79+ * <br>
80+ * //...
81+ * <br>
82+ * // Inside body of sort routine, compare keys this way
83+ * if( keys[i].compareTo( keys[j] ) > 0 )
84+ * // swap keys[i] and keys[j]
85+ * <br>
86+ * //...
87+ * <br>
88+ * // Finally, when we've returned from sort.
89+ * System.out.println( keys[0].getSourceString() );
90+ * System.out.println( keys[1].getSourceString() );
91+ * System.out.println( keys[2].getSourceString() );
92+ * </pre>
93+ * </blockquote>
94+ *
95+ * @see Collator
96+ * @see RuleBasedCollator
97+ * @author Helena Shih
98+ */
99+
100+public abstract class CollationKey implements Comparable<CollationKey> {
101+ /**
102+ * Compare this CollationKey to the target CollationKey. The collation rules of the
103+ * Collator object which created these keys are applied. <strong>Note:</strong>
104+ * CollationKeys created by different Collators can not be compared.
105+ * @param target target CollationKey
106+ * @return Returns an integer value. Value is less than zero if this is less
107+ * than target, value is zero if this and target are equal and value is greater than
108+ * zero if this is greater than target.
109+ * @see java.text.Collator#compare
110+ */
111+ abstract public int compareTo(CollationKey target);
112+
113+ /**
114+ * Returns the String that this CollationKey represents.
115+ */
116+ public String getSourceString() {
117+ return source;
118+ }
119+
120+
121+ /**
122+ * Converts the CollationKey to a sequence of bits. If two CollationKeys
123+ * could be legitimately compared, then one could compare the byte arrays
124+ * for each of those keys to obtain the same result. Byte arrays are
125+ * organized most significant byte first.
126+ */
127+ abstract public byte[] toByteArray();
128+
129+
130+ /**
131+ * CollationKey constructor.
132+ *
133+ * @param source - the source string.
134+ * @exception NullPointerException if <code>source</code> is null.
135+ * @since 1.6
136+ */
137+ protected CollationKey(String source) {
138+ if (source==null){
139+ throw new NullPointerException();
140+ }
141+ this.source = source;
142+ }
143+
144+ final private String source;
145+}
java/pkg/java/text/CollationRules.class+0−0

Binary file not shown.

java/pkg/java/text/CollationRules.java+274−0
@@ -0,0 +1,274 @@
1+/*
2+ * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996,1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+/**
41+ * CollationRules contains the default en_US collation rules as a base
42+ * for building other collation tables.
43+ * <p>Note that decompositions are done before these rules are used,
44+ * so they do not have to contain accented characters, such as A-grave.
45+ * @see RuleBasedCollator
46+ * @see LocaleElements
47+ * @author Helena Shih, Mark Davis
48+ */
49+final class CollationRules {
50+ final static String DEFAULTRULES = new String(
51+ "" // no FRENCH accent order by default, add in French Delta
52+ // IGNORABLES (up to first < character)
53+ // COMPLETELY IGNORE format characters
54+ + "='\u200B'=\u200C=\u200D=\u200E=\u200F"
55+ // Control Characters
56+ + "=\u0000 =\u0001 =\u0002 =\u0003 =\u0004" //null, .. eot
57+ + "=\u0005 =\u0006 =\u0007 =\u0008 ='\u0009'" //enq, ...
58+ + "='\u000b' =\u000e" //vt,, so
59+ + "=\u000f ='\u0010' =\u0011 =\u0012 =\u0013" //si, dle, dc1, dc2, dc3
60+ + "=\u0014 =\u0015 =\u0016 =\u0017 =\u0018" //dc4, nak, syn, etb, can
61+ + "=\u0019 =\u001a =\u001b =\u001c =\u001d" //em, sub, esc, fs, gs
62+ + "=\u001e =\u001f =\u007f" //rs, us, del
63+ //....then the C1 Latin 1 reserved control codes
64+ + "=\u0080 =\u0081 =\u0082 =\u0083 =\u0084 =\u0085"
65+ + "=\u0086 =\u0087 =\u0088 =\u0089 =\u008a =\u008b"
66+ + "=\u008c =\u008d =\u008e =\u008f =\u0090 =\u0091"
67+ + "=\u0092 =\u0093 =\u0094 =\u0095 =\u0096 =\u0097"
68+ + "=\u0098 =\u0099 =\u009a =\u009b =\u009c =\u009d"
69+ + "=\u009e =\u009f"
70+ // IGNORE except for secondary, tertiary difference
71+ // Spaces
72+ + ";'\u0020';'\u00A0'" // spaces
73+ + ";'\u2000';'\u2001';'\u2002';'\u2003';'\u2004'" // spaces
74+ + ";'\u2005';'\u2006';'\u2007';'\u2008';'\u2009'" // spaces
75+ + ";'\u200A';'\u3000';'\uFEFF'" // spaces
76+ + ";'\r' ;'\t' ;'\n';'\f';'\u000b'" // whitespace
77+
78+ // Non-spacing accents
79+
80+ + ";\u0301" // non-spacing acute accent
81+ + ";\u0300" // non-spacing grave accent
82+ + ";\u0306" // non-spacing breve accent
83+ + ";\u0302" // non-spacing circumflex accent
84+ + ";\u030c" // non-spacing caron/hacek accent
85+ + ";\u030a" // non-spacing ring above accent
86+ + ";\u030d" // non-spacing vertical line above
87+ + ";\u0308" // non-spacing diaeresis accent
88+ + ";\u030b" // non-spacing double acute accent
89+ + ";\u0303" // non-spacing tilde accent
90+ + ";\u0307" // non-spacing dot above/overdot accent
91+ + ";\u0304" // non-spacing macron accent
92+ + ";\u0337" // non-spacing short slash overlay (overstruck diacritic)
93+ + ";\u0327" // non-spacing cedilla accent
94+ + ";\u0328" // non-spacing ogonek accent
95+ + ";\u0323" // non-spacing dot-below/underdot accent
96+ + ";\u0332" // non-spacing underscore/underline accent
97+ // with the rest of the general diacritical marks in binary order
98+ + ";\u0305" // non-spacing overscore/overline
99+ + ";\u0309" // non-spacing hook above
100+ + ";\u030e" // non-spacing double vertical line above
101+ + ";\u030f" // non-spacing double grave
102+ + ";\u0310" // non-spacing chandrabindu
103+ + ";\u0311" // non-spacing inverted breve
104+ + ";\u0312" // non-spacing turned comma above/cedilla above
105+ + ";\u0313" // non-spacing comma above
106+ + ";\u0314" // non-spacing reversed comma above
107+ + ";\u0315" // non-spacing comma above right
108+ + ";\u0316" // non-spacing grave below
109+ + ";\u0317" // non-spacing acute below
110+ + ";\u0318" // non-spacing left tack below
111+ + ";\u0319" // non-spacing tack below
112+ + ";\u031a" // non-spacing left angle above
113+ + ";\u031b" // non-spacing horn
114+ + ";\u031c" // non-spacing left half ring below
115+ + ";\u031d" // non-spacing up tack below
116+ + ";\u031e" // non-spacing down tack below
117+ + ";\u031f" // non-spacing plus sign below
118+ + ";\u0320" // non-spacing minus sign below
119+ + ";\u0321" // non-spacing palatalized hook below
120+ + ";\u0322" // non-spacing retroflex hook below
121+ + ";\u0324" // non-spacing double dot below
122+ + ";\u0325" // non-spacing ring below
123+ + ";\u0326" // non-spacing comma below
124+ + ";\u0329" // non-spacing vertical line below
125+ + ";\u032a" // non-spacing bridge below
126+ + ";\u032b" // non-spacing inverted double arch below
127+ + ";\u032c" // non-spacing hacek below
128+ + ";\u032d" // non-spacing circumflex below
129+ + ";\u032e" // non-spacing breve below
130+ + ";\u032f" // non-spacing inverted breve below
131+ + ";\u0330" // non-spacing tilde below
132+ + ";\u0331" // non-spacing macron below
133+ + ";\u0333" // non-spacing double underscore
134+ + ";\u0334" // non-spacing tilde overlay
135+ + ";\u0335" // non-spacing short bar overlay
136+ + ";\u0336" // non-spacing long bar overlay
137+ + ";\u0338" // non-spacing long slash overlay
138+ + ";\u0339" // non-spacing right half ring below
139+ + ";\u033a" // non-spacing inverted bridge below
140+ + ";\u033b" // non-spacing square below
141+ + ";\u033c" // non-spacing seagull below
142+ + ";\u033d" // non-spacing x above
143+ + ";\u033e" // non-spacing vertical tilde
144+ + ";\u033f" // non-spacing double overscore
145+ //+ ";\u0340" // non-spacing grave tone mark == \u0300
146+ //+ ";\u0341" // non-spacing acute tone mark == \u0301
147+ + ";\u0342;"
148+ //+ "\u0343;" // == \u0313
149+ + "\u0344;\u0345;\u0360;\u0361" // newer
150+ + ";\u0483;\u0484;\u0485;\u0486" // Cyrillic accents
151+
152+ + ";\u20D0;\u20D1;\u20D2" // symbol accents
153+ + ";\u20D3;\u20D4;\u20D5" // symbol accents
154+ + ";\u20D6;\u20D7;\u20D8" // symbol accents
155+ + ";\u20D9;\u20DA;\u20DB" // symbol accents
156+ + ";\u20DC;\u20DD;\u20DE" // symbol accents
157+ + ";\u20DF;\u20E0;\u20E1" // symbol accents
158+
159+ + ",'\u002D';\u00AD" // dashes
160+ + ";\u2010;\u2011;\u2012" // dashes
161+ + ";\u2013;\u2014;\u2015" // dashes
162+ + ";\u2212" // dashes
163+
164+ // other punctuation
165+
166+ + "<'\u005f'" // underline/underscore (spacing)
167+ + "<\u00af" // overline or macron (spacing)
168+ + "<'\u002c'" // comma (spacing)
169+ + "<'\u003b'" // semicolon
170+ + "<'\u003a'" // colon
171+ + "<'\u0021'" // exclamation point
172+ + "<\u00a1" // inverted exclamation point
173+ + "<'\u003f'" // question mark
174+ + "<\u00bf" // inverted question mark
175+ + "<'\u002f'" // slash
176+ + "<'\u002e'" // period/full stop
177+ + "<\u00b4" // acute accent (spacing)
178+ + "<'\u0060'" // grave accent (spacing)
179+ + "<'\u005e'" // circumflex accent (spacing)
180+ + "<\u00a8" // diaresis/umlaut accent (spacing)
181+ + "<'\u007e'" // tilde accent (spacing)
182+ + "<\u00b7" // middle dot (spacing)
183+ + "<\u00b8" // cedilla accent (spacing)
184+ + "<'\u0027'" // apostrophe
185+ + "<'\"'" // quotation marks
186+ + "<\u00ab" // left angle quotes
187+ + "<\u00bb" // right angle quotes
188+ + "<'\u0028'" // left parenthesis
189+ + "<'\u0029'" // right parenthesis
190+ + "<'\u005b'" // left bracket
191+ + "<'\u005d'" // right bracket
192+ + "<'\u007b'" // left brace
193+ + "<'\u007d'" // right brace
194+ + "<\u00a7" // section symbol
195+ + "<\u00b6" // paragraph symbol
196+ + "<\u00a9" // copyright symbol
197+ + "<\u00ae" // registered trademark symbol
198+ + "<'\u0040'" // at sign
199+ + "<\u00a4" // international currency symbol
200+ + "<\u0e3f" // baht sign
201+ + "<\u00a2" // cent sign
202+ + "<\u20a1" // colon sign
203+ + "<\u20a2" // cruzeiro sign
204+ + "<'\u0024'" // dollar sign
205+ + "<\u20ab" // dong sign
206+ + "<\u20ac" // euro sign
207+ + "<\u20a3" // franc sign
208+ + "<\u20a4" // lira sign
209+ + "<\u20a5" // mill sign
210+ + "<\u20a6" // naira sign
211+ + "<\u20a7" // peseta sign
212+ + "<\u00a3" // pound-sterling sign
213+ + "<\u20a8" // rupee sign
214+ + "<\u20aa" // new shekel sign
215+ + "<\u20a9" // won sign
216+ + "<\u00a5" // yen sign
217+ + "<'\u002a'" // asterisk
218+ + "<'\\'" // backslash
219+ + "<'\u0026'" // ampersand
220+ + "<'\u0023'" // number sign
221+ + "<'\u0025'" // percent sign
222+ + "<'\u002b'" // plus sign
223+ + "<\u00b1" // plus-or-minus sign
224+ + "<\u00f7" // divide sign
225+ + "<\u00d7" // multiply sign
226+ + "<'\u003c'" // less-than sign
227+ + "<'\u003d'" // equal sign
228+ + "<'\u003e'" // greater-than sign
229+ + "<\u00ac" // end of line symbol/logical NOT symbol
230+ + "<'\u007c'" // vertical line/logical OR symbol
231+ + "<\u00a6" // broken vertical line
232+ + "<\u00b0" // degree symbol
233+ + "<\u00b5" // micro symbol
234+
235+ // NUMERICS
236+
237+ + "<0<1<2<3<4<5<6<7<8<9"
238+ + "<\u00bc<\u00bd<\u00be" // 1/4,1/2,3/4 fractions
239+
240+ // NON-IGNORABLES
241+ + "<a,A"
242+ + "<b,B"
243+ + "<c,C"
244+ + "<d,D"
245+ + "<\u00F0,\u00D0" // eth
246+ + "<e,E"
247+ + "<f,F"
248+ + "<g,G"
249+ + "<h,H"
250+ + "<i,I"
251+ + "<j,J"
252+ + "<k,K"
253+ + "<l,L"
254+ + "<m,M"
255+ + "<n,N"
256+ + "<o,O"
257+ + "<p,P"
258+ + "<q,Q"
259+ + "<r,R"
260+ + "<s, S & SS,\u00DF" // s-zet
261+ + "<t,T"
262+ + "& TH, \u00DE &TH, \u00FE " // thorn
263+ + "<u,U"
264+ + "<v,V"
265+ + "<w,W"
266+ + "<x,X"
267+ + "<y,Y"
268+ + "<z,Z"
269+ + "&AE,\u00C6" // ae & AE ligature
270+ + "&AE,\u00E6"
271+ + "&OE,\u0152" // oe & OE ligature
272+ + "&OE,\u0153"
273+ );
274+}
java/pkg/java/text/Collator$CollatorGetter.class+0−0

Binary file not shown.

java/pkg/java/text/Collator.class+0−0

Binary file not shown.

java/pkg/java/text/Collator.java+553−0
@@ -0,0 +1,553 @@
1+/*
2+ * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.text.spi.CollatorProvider;
42+import java.util.Locale;
43+import java.util.MissingResourceException;
44+import java.util.ResourceBundle;
45+import java.util.spi.LocaleServiceProvider;
46+import sun.misc.SoftCache;
47+import sun.util.resources.LocaleData;
48+import sun.util.LocaleServiceProviderPool;
49+
50+
51+/**
52+ * The <code>Collator</code> class performs locale-sensitive
53+ * <code>String</code> comparison. You use this class to build
54+ * searching and sorting routines for natural language text.
55+ *
56+ * <p>
57+ * <code>Collator</code> is an abstract base class. Subclasses
58+ * implement specific collation strategies. One subclass,
59+ * <code>RuleBasedCollator</code>, is currently provided with
60+ * the Java Platform and is applicable to a wide set of languages. Other
61+ * subclasses may be created to handle more specialized needs.
62+ *
63+ * <p>
64+ * Like other locale-sensitive classes, you can use the static
65+ * factory method, <code>getInstance</code>, to obtain the appropriate
66+ * <code>Collator</code> object for a given locale. You will only need
67+ * to look at the subclasses of <code>Collator</code> if you need
68+ * to understand the details of a particular collation strategy or
69+ * if you need to modify that strategy.
70+ *
71+ * <p>
72+ * The following example shows how to compare two strings using
73+ * the <code>Collator</code> for the default locale.
74+ * <blockquote>
75+ * <pre>
76+ * // Compare two strings in the default locale
77+ * Collator myCollator = Collator.getInstance();
78+ * if( myCollator.compare("abc", "ABC") < 0 )
79+ * System.out.println("abc is less than ABC");
80+ * else
81+ * System.out.println("abc is greater than or equal to ABC");
82+ * </pre>
83+ * </blockquote>
84+ *
85+ * <p>
86+ * You can set a <code>Collator</code>'s <em>strength</em> property
87+ * to determine the level of difference considered significant in
88+ * comparisons. Four strengths are provided: <code>PRIMARY</code>,
89+ * <code>SECONDARY</code>, <code>TERTIARY</code>, and <code>IDENTICAL</code>.
90+ * The exact assignment of strengths to language features is
91+ * locale dependant. For example, in Czech, "e" and "f" are considered
92+ * primary differences, while "e" and "&#283;" are secondary differences,
93+ * "e" and "E" are tertiary differences and "e" and "e" are identical.
94+ * The following shows how both case and accents could be ignored for
95+ * US English.
96+ * <blockquote>
97+ * <pre>
98+ * //Get the Collator for US English and set its strength to PRIMARY
99+ * Collator usCollator = Collator.getInstance(Locale.US);
100+ * usCollator.setStrength(Collator.PRIMARY);
101+ * if( usCollator.compare("abc", "ABC") == 0 ) {
102+ * System.out.println("Strings are equivalent");
103+ * }
104+ * </pre>
105+ * </blockquote>
106+ * <p>
107+ * For comparing <code>String</code>s exactly once, the <code>compare</code>
108+ * method provides the best performance. When sorting a list of
109+ * <code>String</code>s however, it is generally necessary to compare each
110+ * <code>String</code> multiple times. In this case, <code>CollationKey</code>s
111+ * provide better performance. The <code>CollationKey</code> class converts
112+ * a <code>String</code> to a series of bits that can be compared bitwise
113+ * against other <code>CollationKey</code>s. A <code>CollationKey</code> is
114+ * created by a <code>Collator</code> object for a given <code>String</code>.
115+ * <br>
116+ * <strong>Note:</strong> <code>CollationKey</code>s from different
117+ * <code>Collator</code>s can not be compared. See the class description
118+ * for {@link CollationKey}
119+ * for an example using <code>CollationKey</code>s.
120+ *
121+ * @see RuleBasedCollator
122+ * @see CollationKey
123+ * @see CollationElementIterator
124+ * @see Locale
125+ * @author Helena Shih, Laura Werner, Richard Gillam
126+ */
127+
128+public abstract class Collator
129+ implements java.util.Comparator<Object>, Cloneable
130+{
131+ /**
132+ * Collator strength value. When set, only PRIMARY differences are
133+ * considered significant during comparison. The assignment of strengths
134+ * to language features is locale dependant. A common example is for
135+ * different base letters ("a" vs "b") to be considered a PRIMARY difference.
136+ * @see java.text.Collator#setStrength
137+ * @see java.text.Collator#getStrength
138+ */
139+ public final static int PRIMARY = 0;
140+ /**
141+ * Collator strength value. When set, only SECONDARY and above differences are
142+ * considered significant during comparison. The assignment of strengths
143+ * to language features is locale dependant. A common example is for
144+ * different accented forms of the same base letter ("a" vs "\u00E4") to be
145+ * considered a SECONDARY difference.
146+ * @see java.text.Collator#setStrength
147+ * @see java.text.Collator#getStrength
148+ */
149+ public final static int SECONDARY = 1;
150+ /**
151+ * Collator strength value. When set, only TERTIARY and above differences are
152+ * considered significant during comparison. The assignment of strengths
153+ * to language features is locale dependant. A common example is for
154+ * case differences ("a" vs "A") to be considered a TERTIARY difference.
155+ * @see java.text.Collator#setStrength
156+ * @see java.text.Collator#getStrength
157+ */
158+ public final static int TERTIARY = 2;
159+
160+ /**
161+ * Collator strength value. When set, all differences are
162+ * considered significant during comparison. The assignment of strengths
163+ * to language features is locale dependant. A common example is for control
164+ * characters ("&#092;u0001" vs "&#092;u0002") to be considered equal at the
165+ * PRIMARY, SECONDARY, and TERTIARY levels but different at the IDENTICAL
166+ * level. Additionally, differences between pre-composed accents such as
167+ * "&#092;u00C0" (A-grave) and combining accents such as "A&#092;u0300"
168+ * (A, combining-grave) will be considered significant at the IDENTICAL
169+ * level if decomposition is set to NO_DECOMPOSITION.
170+ */
171+ public final static int IDENTICAL = 3;
172+
173+ /**
174+ * Decomposition mode value. With NO_DECOMPOSITION
175+ * set, accented characters will not be decomposed for collation. This
176+ * is the default setting and provides the fastest collation but
177+ * will only produce correct results for languages that do not use accents.
178+ * @see java.text.Collator#getDecomposition
179+ * @see java.text.Collator#setDecomposition
180+ */
181+ public final static int NO_DECOMPOSITION = 0;
182+
183+ /**
184+ * Decomposition mode value. With CANONICAL_DECOMPOSITION
185+ * set, characters that are canonical variants according to Unicode
186+ * standard will be decomposed for collation. This should be used to get
187+ * correct collation of accented characters.
188+ * <p>
189+ * CANONICAL_DECOMPOSITION corresponds to Normalization Form D as
190+ * described in
191+ * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode
192+ * Technical Report #15</a>.
193+ * @see java.text.Collator#getDecomposition
194+ * @see java.text.Collator#setDecomposition
195+ */
196+ public final static int CANONICAL_DECOMPOSITION = 1;
197+
198+ /**
199+ * Decomposition mode value. With FULL_DECOMPOSITION
200+ * set, both Unicode canonical variants and Unicode compatibility variants
201+ * will be decomposed for collation. This causes not only accented
202+ * characters to be collated, but also characters that have special formats
203+ * to be collated with their norminal form. For example, the half-width and
204+ * full-width ASCII and Katakana characters are then collated together.
205+ * FULL_DECOMPOSITION is the most complete and therefore the slowest
206+ * decomposition mode.
207+ * <p>
208+ * FULL_DECOMPOSITION corresponds to Normalization Form KD as
209+ * described in
210+ * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">Unicode
211+ * Technical Report #15</a>.
212+ * @see java.text.Collator#getDecomposition
213+ * @see java.text.Collator#setDecomposition
214+ */
215+ public final static int FULL_DECOMPOSITION = 2;
216+
217+ /**
218+ * Gets the Collator for the current default locale.
219+ * The default locale is determined by java.util.Locale.getDefault.
220+ * @return the Collator for the default locale.(for example, en_US)
221+ * @see java.util.Locale#getDefault
222+ */
223+ public static synchronized Collator getInstance() {
224+ return getInstance(Locale.getDefault());
225+ }
226+
227+ /**
228+ * Gets the Collator for the desired locale.
229+ * @param desiredLocale the desired locale.
230+ * @return the Collator for the desired locale.
231+ * @see java.util.Locale
232+ * @see java.util.ResourceBundle
233+ */
234+ public static synchronized
235+ Collator getInstance(Locale desiredLocale)
236+ {
237+ Collator result = (Collator) cache.get(desiredLocale);
238+ if (result != null) {
239+ return (Collator)result.clone(); // make the world safe
240+ }
241+
242+ // Check whether a provider can provide an implementation that's closer
243+ // to the requested locale than what the Java runtime itself can provide.
244+ LocaleServiceProviderPool pool =
245+ LocaleServiceProviderPool.getPool(CollatorProvider.class);
246+ if (pool.hasProviders()) {
247+ Collator providersInstance = pool.getLocalizedObject(
248+ CollatorGetter.INSTANCE,
249+ desiredLocale,
250+ desiredLocale);
251+ if (providersInstance != null) {
252+ return providersInstance;
253+ }
254+ }
255+
256+ // Load the resource of the desired locale from resource
257+ // manager.
258+ String colString = "";
259+ try {
260+ ResourceBundle resource = LocaleData.getCollationData(desiredLocale);
261+
262+ colString = resource.getString("Rule");
263+ } catch (MissingResourceException e) {
264+ // Use default values
265+ }
266+ try
267+ {
268+ result = new RuleBasedCollator( CollationRules.DEFAULTRULES +
269+ colString,
270+ CANONICAL_DECOMPOSITION );
271+ }
272+ catch(ParseException foo)
273+ {
274+ // predefined tables should contain correct grammar
275+ try {
276+ result = new RuleBasedCollator( CollationRules.DEFAULTRULES );
277+ } catch (ParseException bar) {
278+ // do nothing
279+ }
280+ }
281+ // Now that RuleBasedCollator adds expansions for pre-composed characters
282+ // into their decomposed equivalents, the default collators don't need
283+ // to have decomposition turned on. Laura, 5/5/98, bug 4114077
284+ result.setDecomposition(NO_DECOMPOSITION);
285+
286+ cache.put(desiredLocale,result);
287+ return (Collator)result.clone();
288+ }
289+
290+ /**
291+ * Compares the source string to the target string according to the
292+ * collation rules for this Collator. Returns an integer less than,
293+ * equal to or greater than zero depending on whether the source String is
294+ * less than, equal to or greater than the target string. See the Collator
295+ * class description for an example of use.
296+ * <p>
297+ * For a one time comparison, this method has the best performance. If a
298+ * given String will be involved in multiple comparisons, CollationKey.compareTo
299+ * has the best performance. See the Collator class description for an example
300+ * using CollationKeys.
301+ * @param source the source string.
302+ * @param target the target string.
303+ * @return Returns an integer value. Value is less than zero if source is less than
304+ * target, value is zero if source and target are equal, value is greater than zero
305+ * if source is greater than target.
306+ * @see java.text.CollationKey
307+ * @see java.text.Collator#getCollationKey
308+ */
309+ public abstract int compare(String source, String target);
310+
311+ /**
312+ * Compares its two arguments for order. Returns a negative integer,
313+ * zero, or a positive integer as the first argument is less than, equal
314+ * to, or greater than the second.
315+ * <p>
316+ * This implementation merely returns
317+ * <code> compare((String)o1, (String)o2) </code>.
318+ *
319+ * @return a negative integer, zero, or a positive integer as the
320+ * first argument is less than, equal to, or greater than the
321+ * second.
322+ * @exception ClassCastException the arguments cannot be cast to Strings.
323+ * @see java.util.Comparator
324+ * @since 1.2
325+ */
326+ public int compare(Object o1, Object o2) {
327+ return compare((String)o1, (String)o2);
328+ }
329+
330+ /**
331+ * Transforms the String into a series of bits that can be compared bitwise
332+ * to other CollationKeys. CollationKeys provide better performance than
333+ * Collator.compare when Strings are involved in multiple comparisons.
334+ * See the Collator class description for an example using CollationKeys.
335+ * @param source the string to be transformed into a collation key.
336+ * @return the CollationKey for the given String based on this Collator's collation
337+ * rules. If the source String is null, a null CollationKey is returned.
338+ * @see java.text.CollationKey
339+ * @see java.text.Collator#compare
340+ */
341+ public abstract CollationKey getCollationKey(String source);
342+
343+ /**
344+ * Convenience method for comparing the equality of two strings based on
345+ * this Collator's collation rules.
346+ * @param source the source string to be compared with.
347+ * @param target the target string to be compared with.
348+ * @return true if the strings are equal according to the collation
349+ * rules. false, otherwise.
350+ * @see java.text.Collator#compare
351+ */
352+ public boolean equals(String source, String target)
353+ {
354+ return (compare(source, target) == Collator.EQUAL);
355+ }
356+
357+ /**
358+ * Returns this Collator's strength property. The strength property determines
359+ * the minimum level of difference considered significant during comparison.
360+ * See the Collator class description for an example of use.
361+ * @return this Collator's current strength property.
362+ * @see java.text.Collator#setStrength
363+ * @see java.text.Collator#PRIMARY
364+ * @see java.text.Collator#SECONDARY
365+ * @see java.text.Collator#TERTIARY
366+ * @see java.text.Collator#IDENTICAL
367+ */
368+ public synchronized int getStrength()
369+ {
370+ return strength;
371+ }
372+
373+ /**
374+ * Sets this Collator's strength property. The strength property determines
375+ * the minimum level of difference considered significant during comparison.
376+ * See the Collator class description for an example of use.
377+ * @param newStrength the new strength value.
378+ * @see java.text.Collator#getStrength
379+ * @see java.text.Collator#PRIMARY
380+ * @see java.text.Collator#SECONDARY
381+ * @see java.text.Collator#TERTIARY
382+ * @see java.text.Collator#IDENTICAL
383+ * @exception IllegalArgumentException If the new strength value is not one of
384+ * PRIMARY, SECONDARY, TERTIARY or IDENTICAL.
385+ */
386+ public synchronized void setStrength(int newStrength) {
387+ if ((newStrength != PRIMARY) &&
388+ (newStrength != SECONDARY) &&
389+ (newStrength != TERTIARY) &&
390+ (newStrength != IDENTICAL))
391+ throw new IllegalArgumentException("Incorrect comparison level.");
392+ strength = newStrength;
393+ }
394+
395+ /**
396+ * Get the decomposition mode of this Collator. Decomposition mode
397+ * determines how Unicode composed characters are handled. Adjusting
398+ * decomposition mode allows the user to select between faster and more
399+ * complete collation behavior.
400+ * <p>The three values for decomposition mode are:
401+ * <UL>
402+ * <LI>NO_DECOMPOSITION,
403+ * <LI>CANONICAL_DECOMPOSITION
404+ * <LI>FULL_DECOMPOSITION.
405+ * </UL>
406+ * See the documentation for these three constants for a description
407+ * of their meaning.
408+ * @return the decomposition mode
409+ * @see java.text.Collator#setDecomposition
410+ * @see java.text.Collator#NO_DECOMPOSITION
411+ * @see java.text.Collator#CANONICAL_DECOMPOSITION
412+ * @see java.text.Collator#FULL_DECOMPOSITION
413+ */
414+ public synchronized int getDecomposition()
415+ {
416+ return decmp;
417+ }
418+ /**
419+ * Set the decomposition mode of this Collator. See getDecomposition
420+ * for a description of decomposition mode.
421+ * @param decompositionMode the new decomposition mode.
422+ * @see java.text.Collator#getDecomposition
423+ * @see java.text.Collator#NO_DECOMPOSITION
424+ * @see java.text.Collator#CANONICAL_DECOMPOSITION
425+ * @see java.text.Collator#FULL_DECOMPOSITION
426+ * @exception IllegalArgumentException If the given value is not a valid decomposition
427+ * mode.
428+ */
429+ public synchronized void setDecomposition(int decompositionMode) {
430+ if ((decompositionMode != NO_DECOMPOSITION) &&
431+ (decompositionMode != CANONICAL_DECOMPOSITION) &&
432+ (decompositionMode != FULL_DECOMPOSITION))
433+ throw new IllegalArgumentException("Wrong decomposition mode.");
434+ decmp = decompositionMode;
435+ }
436+
437+ /**
438+ * Returns an array of all locales for which the
439+ * <code>getInstance</code> methods of this class can return
440+ * localized instances.
441+ * The returned array represents the union of locales supported
442+ * by the Java runtime and by installed
443+ * {@link java.text.spi.CollatorProvider CollatorProvider} implementations.
444+ * It must contain at least a Locale instance equal to
445+ * {@link java.util.Locale#US Locale.US}.
446+ *
447+ * @return An array of locales for which localized
448+ * <code>Collator</code> instances are available.
449+ */
450+ public static synchronized Locale[] getAvailableLocales() {
451+ LocaleServiceProviderPool pool =
452+ LocaleServiceProviderPool.getPool(CollatorProvider.class);
453+ return pool.getAvailableLocales();
454+ }
455+
456+ /**
457+ * Overrides Cloneable
458+ */
459+ public Object clone()
460+ {
461+ try {
462+ return (Collator)super.clone();
463+ } catch (CloneNotSupportedException e) {
464+ throw new InternalError();
465+ }
466+ }
467+
468+ /**
469+ * Compares the equality of two Collators.
470+ * @param that the Collator to be compared with this.
471+ * @return true if this Collator is the same as that Collator;
472+ * false otherwise.
473+ */
474+ public boolean equals(Object that)
475+ {
476+ if (this == that) return true;
477+ if (that == null) return false;
478+ if (getClass() != that.getClass()) return false;
479+ Collator other = (Collator) that;
480+ return ((strength == other.strength) &&
481+ (decmp == other.decmp));
482+ }
483+
484+ /**
485+ * Generates the hash code for this Collator.
486+ */
487+ abstract public int hashCode();
488+
489+ /**
490+ * Default constructor. This constructor is
491+ * protected so subclasses can get access to it. Users typically create
492+ * a Collator sub-class by calling the factory method getInstance.
493+ * @see java.text.Collator#getInstance
494+ */
495+ protected Collator()
496+ {
497+ strength = TERTIARY;
498+ decmp = CANONICAL_DECOMPOSITION;
499+ }
500+
501+ private int strength = 0;
502+ private int decmp = 0;
503+ private static SoftCache cache = new SoftCache();
504+
505+ //
506+ // FIXME: These three constants should be removed.
507+ //
508+ /**
509+ * LESS is returned if source string is compared to be less than target
510+ * string in the compare() method.
511+ * @see java.text.Collator#compare
512+ */
513+ final static int LESS = -1;
514+ /**
515+ * EQUAL is returned if source string is compared to be equal to target
516+ * string in the compare() method.
517+ * @see java.text.Collator#compare
518+ */
519+ final static int EQUAL = 0;
520+ /**
521+ * GREATER is returned if source string is compared to be greater than
522+ * target string in the compare() method.
523+ * @see java.text.Collator#compare
524+ */
525+ final static int GREATER = 1;
526+
527+ /**
528+ * Obtains a Collator instance from a CollatorProvider
529+ * implementation.
530+ */
531+ private static class CollatorGetter
532+ implements LocaleServiceProviderPool.LocalizedObjectGetter<CollatorProvider, Collator> {
533+ private static final CollatorGetter INSTANCE = new CollatorGetter();
534+
535+ public Collator getObject(CollatorProvider collatorProvider,
536+ Locale locale,
537+ String key,
538+ Object... params) {
539+ assert params.length == 1;
540+ Collator result = collatorProvider.getInstance(locale);
541+ if (result != null) {
542+ // put this Collator instance in the cache for two locales, one
543+ // is for the desired locale, and the other is for the actual
544+ // locale where the provider is found, which may be a fall back locale.
545+ cache.put((Locale)params[0], result);
546+ cache.put(locale, result);
547+ return (Collator)result.clone();
548+ }
549+
550+ return null;
551+ }
552+ }
553+ }
java/pkg/java/text/DateFormat$DateFormatGetter.class+0−0

Binary file not shown.

java/pkg/java/text/DateFormat$Field.class+0−0

Binary file not shown.

java/pkg/java/text/DateFormat.class+0−0

Binary file not shown.

java/pkg/java/text/DateFormat.java+1030−0
@@ -0,0 +1,1030 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.InvalidObjectException;
42+import java.text.spi.DateFormatProvider;
43+import java.util.Calendar;
44+import java.util.Date;
45+import java.util.GregorianCalendar;
46+import java.util.HashMap;
47+import java.util.Locale;
48+import java.util.Map;
49+import java.util.MissingResourceException;
50+import java.util.ResourceBundle;
51+import java.util.TimeZone;
52+import java.util.spi.LocaleServiceProvider;
53+import sun.util.LocaleServiceProviderPool;
54+
55+/**
56+ * {@code DateFormat} is an abstract class for date/time formatting subclasses which
57+ * formats and parses dates or time in a language-independent manner.
58+ * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
59+ * formatting (i.e., date -> text), parsing (text -> date), and
60+ * normalization. The date is represented as a <code>Date</code> object or
61+ * as the milliseconds since January 1, 1970, 00:00:00 GMT.
62+ *
63+ * <p>{@code DateFormat} provides many class methods for obtaining default date/time
64+ * formatters based on the default or a given locale and a number of formatting
65+ * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
66+ * detail and examples of using these styles are provided in the method
67+ * descriptions.
68+ *
69+ * <p>{@code DateFormat} helps you to format and parse dates for any locale.
70+ * Your code can be completely independent of the locale conventions for
71+ * months, days of the week, or even the calendar format: lunar vs. solar.
72+ *
73+ * <p>To format a date for the current Locale, use one of the
74+ * static factory methods:
75+ * <pre>
76+ * myString = DateFormat.getDateInstance().format(myDate);
77+ * </pre>
78+ * <p>If you are formatting multiple dates, it is
79+ * more efficient to get the format and use it multiple times so that
80+ * the system doesn't have to fetch the information about the local
81+ * language and country conventions multiple times.
82+ * <pre>
83+ * DateFormat df = DateFormat.getDateInstance();
84+ * for (int i = 0; i < myDate.length; ++i) {
85+ * output.println(df.format(myDate[i]) + "; ");
86+ * }
87+ * </pre>
88+ * <p>To format a date for a different Locale, specify it in the
89+ * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
90+ * <pre>
91+ * DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
92+ * </pre>
93+ * <p>You can use a DateFormat to parse also.
94+ * <pre>
95+ * myDate = df.parse(myString);
96+ * </pre>
97+ * <p>Use {@code getDateInstance} to get the normal date format for that country.
98+ * There are other static factory methods available.
99+ * Use {@code getTimeInstance} to get the time format for that country.
100+ * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
101+ * different options to these factory methods to control the length of the
102+ * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
103+ * on the locale, but generally:
104+ * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
105+ * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
106+ * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
107+ * <li>{@link #FULL} is pretty completely specified, such as
108+ * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
109+ * </ul>
110+ *
111+ * <p>You can also set the time zone on the format if you wish.
112+ * If you want even more control over the format or parsing,
113+ * (or want to give your users more control),
114+ * you can try casting the {@code DateFormat} you get from the factory methods
115+ * to a {@link SimpleDateFormat}. This will work for the majority
116+ * of countries; just remember to put it in a {@code try} block in case you
117+ * encounter an unusual one.
118+ *
119+ * <p>You can also use forms of the parse and format methods with
120+ * {@link ParsePosition} and {@link FieldPosition} to
121+ * allow you to
122+ * <ul><li>progressively parse through pieces of a string.
123+ * <li>align any particular field, or find out where it is for selection
124+ * on the screen.
125+ * </ul>
126+ *
127+ * <h4><a name="synchronization">Synchronization</a></h4>
128+ *
129+ * <p>
130+ * Date formats are not synchronized.
131+ * It is recommended to create separate format instances for each thread.
132+ * If multiple threads access a format concurrently, it must be synchronized
133+ * externally.
134+ *
135+ * @see Format
136+ * @see NumberFormat
137+ * @see SimpleDateFormat
138+ * @see java.util.Calendar
139+ * @see java.util.GregorianCalendar
140+ * @see java.util.TimeZone
141+ * @author Mark Davis, Chen-Lieh Huang, Alan Liu
142+ */
143+public abstract class DateFormat extends Format {
144+
145+ /**
146+ * The {@link Calendar} instance used for calculating the date-time fields
147+ * and the instant of time. This field is used for both formatting and
148+ * parsing.
149+ *
150+ * <p>Subclasses should initialize this field to a {@link Calendar}
151+ * appropriate for the {@link Locale} associated with this
152+ * <code>DateFormat</code>.
153+ * @serial
154+ */
155+ protected Calendar calendar;
156+
157+ /**
158+ * The number formatter that <code>DateFormat</code> uses to format numbers
159+ * in dates and times. Subclasses should initialize this to a number format
160+ * appropriate for the locale associated with this <code>DateFormat</code>.
161+ * @serial
162+ */
163+ protected NumberFormat numberFormat;
164+
165+ /**
166+ * Useful constant for ERA field alignment.
167+ * Used in FieldPosition of date/time formatting.
168+ */
169+ public final static int ERA_FIELD = 0;
170+ /**
171+ * Useful constant for YEAR field alignment.
172+ * Used in FieldPosition of date/time formatting.
173+ */
174+ public final static int YEAR_FIELD = 1;
175+ /**
176+ * Useful constant for MONTH field alignment.
177+ * Used in FieldPosition of date/time formatting.
178+ */
179+ public final static int MONTH_FIELD = 2;
180+ /**
181+ * Useful constant for DATE field alignment.
182+ * Used in FieldPosition of date/time formatting.
183+ */
184+ public final static int DATE_FIELD = 3;
185+ /**
186+ * Useful constant for one-based HOUR_OF_DAY field alignment.
187+ * Used in FieldPosition of date/time formatting.
188+ * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
189+ * For example, 23:59 + 01:00 results in 24:59.
190+ */
191+ public final static int HOUR_OF_DAY1_FIELD = 4;
192+ /**
193+ * Useful constant for zero-based HOUR_OF_DAY field alignment.
194+ * Used in FieldPosition of date/time formatting.
195+ * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
196+ * For example, 23:59 + 01:00 results in 00:59.
197+ */
198+ public final static int HOUR_OF_DAY0_FIELD = 5;
199+ /**
200+ * Useful constant for MINUTE field alignment.
201+ * Used in FieldPosition of date/time formatting.
202+ */
203+ public final static int MINUTE_FIELD = 6;
204+ /**
205+ * Useful constant for SECOND field alignment.
206+ * Used in FieldPosition of date/time formatting.
207+ */
208+ public final static int SECOND_FIELD = 7;
209+ /**
210+ * Useful constant for MILLISECOND field alignment.
211+ * Used in FieldPosition of date/time formatting.
212+ */
213+ public final static int MILLISECOND_FIELD = 8;
214+ /**
215+ * Useful constant for DAY_OF_WEEK field alignment.
216+ * Used in FieldPosition of date/time formatting.
217+ */
218+ public final static int DAY_OF_WEEK_FIELD = 9;
219+ /**
220+ * Useful constant for DAY_OF_YEAR field alignment.
221+ * Used in FieldPosition of date/time formatting.
222+ */
223+ public final static int DAY_OF_YEAR_FIELD = 10;
224+ /**
225+ * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
226+ * Used in FieldPosition of date/time formatting.
227+ */
228+ public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
229+ /**
230+ * Useful constant for WEEK_OF_YEAR field alignment.
231+ * Used in FieldPosition of date/time formatting.
232+ */
233+ public final static int WEEK_OF_YEAR_FIELD = 12;
234+ /**
235+ * Useful constant for WEEK_OF_MONTH field alignment.
236+ * Used in FieldPosition of date/time formatting.
237+ */
238+ public final static int WEEK_OF_MONTH_FIELD = 13;
239+ /**
240+ * Useful constant for AM_PM field alignment.
241+ * Used in FieldPosition of date/time formatting.
242+ */
243+ public final static int AM_PM_FIELD = 14;
244+ /**
245+ * Useful constant for one-based HOUR field alignment.
246+ * Used in FieldPosition of date/time formatting.
247+ * HOUR1_FIELD is used for the one-based 12-hour clock.
248+ * For example, 11:30 PM + 1 hour results in 12:30 AM.
249+ */
250+ public final static int HOUR1_FIELD = 15;
251+ /**
252+ * Useful constant for zero-based HOUR field alignment.
253+ * Used in FieldPosition of date/time formatting.
254+ * HOUR0_FIELD is used for the zero-based 12-hour clock.
255+ * For example, 11:30 PM + 1 hour results in 00:30 AM.
256+ */
257+ public final static int HOUR0_FIELD = 16;
258+ /**
259+ * Useful constant for TIMEZONE field alignment.
260+ * Used in FieldPosition of date/time formatting.
261+ */
262+ public final static int TIMEZONE_FIELD = 17;
263+
264+ // Proclaim serial compatibility with 1.1 FCS
265+ private static final long serialVersionUID = 7218322306649953788L;
266+
267+ /**
268+ * Overrides Format.
269+ * Formats a time object into a time string. Examples of time objects
270+ * are a time value expressed in milliseconds and a Date object.
271+ * @param obj must be a Number or a Date.
272+ * @param toAppendTo the string buffer for the returning time string.
273+ * @return the string buffer passed in as toAppendTo, with formatted text appended.
274+ * @param fieldPosition keeps track of the position of the field
275+ * within the returned string.
276+ * On input: an alignment field,
277+ * if desired. On output: the offsets of the alignment field. For
278+ * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
279+ * if the given fieldPosition is DateFormat.YEAR_FIELD, the
280+ * begin index and end index of fieldPosition will be set to
281+ * 0 and 4, respectively.
282+ * Notice that if the same time field appears
283+ * more than once in a pattern, the fieldPosition will be set for the first
284+ * occurrence of that time field. For instance, formatting a Date to
285+ * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
286+ * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
287+ * the begin index and end index of fieldPosition will be set to
288+ * 5 and 8, respectively, for the first occurrence of the timezone
289+ * pattern character 'z'.
290+ * @see java.text.Format
291+ */
292+ public final StringBuffer format(Object obj, StringBuffer toAppendTo,
293+ FieldPosition fieldPosition)
294+ {
295+ if (obj instanceof Date)
296+ return format( (Date)obj, toAppendTo, fieldPosition );
297+ else if (obj instanceof Number)
298+ return format( new Date(((Number)obj).longValue()),
299+ toAppendTo, fieldPosition );
300+ else
301+ throw new IllegalArgumentException("Cannot format given Object as a Date");
302+ }
303+
304+ /**
305+ * Formats a Date into a date/time string.
306+ * @param date a Date to be formatted into a date/time string.
307+ * @param toAppendTo the string buffer for the returning date/time string.
308+ * @param fieldPosition keeps track of the position of the field
309+ * within the returned string.
310+ * On input: an alignment field,
311+ * if desired. On output: the offsets of the alignment field. For
312+ * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
313+ * if the given fieldPosition is DateFormat.YEAR_FIELD, the
314+ * begin index and end index of fieldPosition will be set to
315+ * 0 and 4, respectively.
316+ * Notice that if the same time field appears
317+ * more than once in a pattern, the fieldPosition will be set for the first
318+ * occurrence of that time field. For instance, formatting a Date to
319+ * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
320+ * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
321+ * the begin index and end index of fieldPosition will be set to
322+ * 5 and 8, respectively, for the first occurrence of the timezone
323+ * pattern character 'z'.
324+ * @return the string buffer passed in as toAppendTo, with formatted text appended.
325+ */
326+ public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
327+ FieldPosition fieldPosition);
328+
329+ /**
330+ * Formats a Date into a date/time string.
331+ * @param date the time value to be formatted into a time string.
332+ * @return the formatted time string.
333+ */
334+ public final String format(Date date)
335+ {
336+ return format(date, new StringBuffer(),
337+ DontCareFieldPosition.INSTANCE).toString();
338+ }
339+
340+ /**
341+ * Parses text from the beginning of the given string to produce a date.
342+ * The method may not use the entire text of the given string.
343+ * <p>
344+ * See the {@link #parse(String, ParsePosition)} method for more information
345+ * on date parsing.
346+ *
347+ * @param source A <code>String</code> whose beginning should be parsed.
348+ * @return A <code>Date</code> parsed from the string.
349+ * @exception ParseException if the beginning of the specified string
350+ * cannot be parsed.
351+ */
352+ public Date parse(String source) throws ParseException
353+ {
354+ ParsePosition pos = new ParsePosition(0);
355+ Date result = parse(source, pos);
356+ if (pos.index == 0)
357+ throw new ParseException("Unparseable date: \"" + source + "\"" ,
358+ pos.errorIndex);
359+ return result;
360+ }
361+
362+ /**
363+ * Parse a date/time string according to the given parse position. For
364+ * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
365+ * that is equivalent to {@code Date(837039900000L)}.
366+ *
367+ * <p> By default, parsing is lenient: If the input is not in the form used
368+ * by this object's format method but can still be parsed as a date, then
369+ * the parse succeeds. Clients may insist on strict adherence to the
370+ * format by calling {@link #setLenient(boolean) setLenient(false)}.
371+ *
372+ * <p>This parsing operation uses the {@link #calendar} to produce
373+ * a {@code Date}. As a result, the {@code calendar}'s date-time
374+ * fields and the {@code TimeZone} value may have been
375+ * overwritten, depending on subclass implementations. Any {@code
376+ * TimeZone} value that has previously been set by a call to
377+ * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
378+ * to be restored for further operations.
379+ *
380+ * @param source The date/time string to be parsed
381+ *
382+ * @param pos On input, the position at which to start parsing; on
383+ * output, the position at which parsing terminated, or the
384+ * start position if the parse failed.
385+ *
386+ * @return A {@code Date}, or {@code null} if the input could not be parsed
387+ */
388+ public abstract Date parse(String source, ParsePosition pos);
389+
390+ /**
391+ * Parses text from a string to produce a <code>Date</code>.
392+ * <p>
393+ * The method attempts to parse text starting at the index given by
394+ * <code>pos</code>.
395+ * If parsing succeeds, then the index of <code>pos</code> is updated
396+ * to the index after the last character used (parsing does not necessarily
397+ * use all characters up to the end of the string), and the parsed
398+ * date is returned. The updated <code>pos</code> can be used to
399+ * indicate the starting point for the next call to this method.
400+ * If an error occurs, then the index of <code>pos</code> is not
401+ * changed, the error index of <code>pos</code> is set to the index of
402+ * the character where the error occurred, and null is returned.
403+ * <p>
404+ * See the {@link #parse(String, ParsePosition)} method for more information
405+ * on date parsing.
406+ *
407+ * @param source A <code>String</code>, part of which should be parsed.
408+ * @param pos A <code>ParsePosition</code> object with index and error
409+ * index information as described above.
410+ * @return A <code>Date</code> parsed from the string. In case of
411+ * error, returns null.
412+ * @exception NullPointerException if <code>pos</code> is null.
413+ */
414+ public Object parseObject(String source, ParsePosition pos) {
415+ return parse(source, pos);
416+ }
417+
418+ /**
419+ * Constant for full style pattern.
420+ */
421+ public static final int FULL = 0;
422+ /**
423+ * Constant for long style pattern.
424+ */
425+ public static final int LONG = 1;
426+ /**
427+ * Constant for medium style pattern.
428+ */
429+ public static final int MEDIUM = 2;
430+ /**
431+ * Constant for short style pattern.
432+ */
433+ public static final int SHORT = 3;
434+ /**
435+ * Constant for default style pattern. Its value is MEDIUM.
436+ */
437+ public static final int DEFAULT = MEDIUM;
438+
439+ /**
440+ * Gets the time formatter with the default formatting style
441+ * for the default locale.
442+ * @return a time formatter.
443+ */
444+ public final static DateFormat getTimeInstance()
445+ {
446+ return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
447+ }
448+
449+ /**
450+ * Gets the time formatter with the given formatting style
451+ * for the default locale.
452+ * @param style the given formatting style. For example,
453+ * SHORT for "h:mm a" in the US locale.
454+ * @return a time formatter.
455+ */
456+ public final static DateFormat getTimeInstance(int style)
457+ {
458+ return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
459+ }
460+
461+ /**
462+ * Gets the time formatter with the given formatting style
463+ * for the given locale.
464+ * @param style the given formatting style. For example,
465+ * SHORT for "h:mm a" in the US locale.
466+ * @param aLocale the given locale.
467+ * @return a time formatter.
468+ */
469+ public final static DateFormat getTimeInstance(int style,
470+ Locale aLocale)
471+ {
472+ return get(style, 0, 1, aLocale);
473+ }
474+
475+ /**
476+ * Gets the date formatter with the default formatting style
477+ * for the default locale.
478+ * @return a date formatter.
479+ */
480+ public final static DateFormat getDateInstance()
481+ {
482+ return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
483+ }
484+
485+ /**
486+ * Gets the date formatter with the given formatting style
487+ * for the default locale.
488+ * @param style the given formatting style. For example,
489+ * SHORT for "M/d/yy" in the US locale.
490+ * @return a date formatter.
491+ */
492+ public final static DateFormat getDateInstance(int style)
493+ {
494+ return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
495+ }
496+
497+ /**
498+ * Gets the date formatter with the given formatting style
499+ * for the given locale.
500+ * @param style the given formatting style. For example,
501+ * SHORT for "M/d/yy" in the US locale.
502+ * @param aLocale the given locale.
503+ * @return a date formatter.
504+ */
505+ public final static DateFormat getDateInstance(int style,
506+ Locale aLocale)
507+ {
508+ return get(0, style, 2, aLocale);
509+ }
510+
511+ /**
512+ * Gets the date/time formatter with the default formatting style
513+ * for the default locale.
514+ * @return a date/time formatter.
515+ */
516+ public final static DateFormat getDateTimeInstance()
517+ {
518+ return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
519+ }
520+
521+ /**
522+ * Gets the date/time formatter with the given date and time
523+ * formatting styles for the default locale.
524+ * @param dateStyle the given date formatting style. For example,
525+ * SHORT for "M/d/yy" in the US locale.
526+ * @param timeStyle the given time formatting style. For example,
527+ * SHORT for "h:mm a" in the US locale.
528+ * @return a date/time formatter.
529+ */
530+ public final static DateFormat getDateTimeInstance(int dateStyle,
531+ int timeStyle)
532+ {
533+ return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
534+ }
535+
536+ /**
537+ * Gets the date/time formatter with the given formatting styles
538+ * for the given locale.
539+ * @param dateStyle the given date formatting style.
540+ * @param timeStyle the given time formatting style.
541+ * @param aLocale the given locale.
542+ * @return a date/time formatter.
543+ */
544+ public final static DateFormat
545+ getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
546+ {
547+ return get(timeStyle, dateStyle, 3, aLocale);
548+ }
549+
550+ /**
551+ * Get a default date/time formatter that uses the SHORT style for both the
552+ * date and the time.
553+ */
554+ public final static DateFormat getInstance() {
555+ return getDateTimeInstance(SHORT, SHORT);
556+ }
557+
558+ /**
559+ * Returns an array of all locales for which the
560+ * <code>get*Instance</code> methods of this class can return
561+ * localized instances.
562+ * The returned array represents the union of locales supported by the Java
563+ * runtime and by installed
564+ * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
565+ * It must contain at least a <code>Locale</code> instance equal to
566+ * {@link java.util.Locale#US Locale.US}.
567+ *
568+ * @return An array of locales for which localized
569+ * <code>DateFormat</code> instances are available.
570+ */
571+ public static Locale[] getAvailableLocales()
572+ {
573+ LocaleServiceProviderPool pool =
574+ LocaleServiceProviderPool.getPool(DateFormatProvider.class);
575+ return pool.getAvailableLocales();
576+ }
577+
578+ /**
579+ * Set the calendar to be used by this date format. Initially, the default
580+ * calendar for the specified or default locale is used.
581+ *
582+ * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
583+ * #isLenient() leniency} values that have previously been set are
584+ * overwritten by {@code newCalendar}'s values.
585+ *
586+ * @param newCalendar the new {@code Calendar} to be used by the date format
587+ */
588+ public void setCalendar(Calendar newCalendar)
589+ {
590+ this.calendar = newCalendar;
591+ }
592+
593+ /**
594+ * Gets the calendar associated with this date/time formatter.
595+ *
596+ * @return the calendar associated with this date/time formatter.
597+ */
598+ public Calendar getCalendar()
599+ {
600+ return calendar;
601+ }
602+
603+ /**
604+ * Allows you to set the number formatter.
605+ * @param newNumberFormat the given new NumberFormat.
606+ */
607+ public void setNumberFormat(NumberFormat newNumberFormat)
608+ {
609+ this.numberFormat = newNumberFormat;
610+ }
611+
612+ /**
613+ * Gets the number formatter which this date/time formatter uses to
614+ * format and parse a time.
615+ * @return the number formatter which this date/time formatter uses.
616+ */
617+ public NumberFormat getNumberFormat()
618+ {
619+ return numberFormat;
620+ }
621+
622+ /**
623+ * Sets the time zone for the calendar of this {@code DateFormat} object.
624+ * This method is equivalent to the following call.
625+ * <blockquote><pre>
626+ * getCalendar().setTimeZone(zone)
627+ * </pre></blockquote>
628+ *
629+ * <p>The {@code TimeZone} set by this method is overwritten by a
630+ * {@link #setCalendar(java.util.Calendar) setCalendar} call.
631+ *
632+ * <p>The {@code TimeZone} set by this method may be overwritten as
633+ * a result of a call to the parse method.
634+ *
635+ * @param zone the given new time zone.
636+ */
637+ public void setTimeZone(TimeZone zone)
638+ {
639+ calendar.setTimeZone(zone);
640+ }
641+
642+ /**
643+ * Gets the time zone.
644+ * This method is equivalent to the following call.
645+ * <blockquote><pre>
646+ * getCalendar().getTimeZone()
647+ * </pre></blockquote>
648+ *
649+ * @return the time zone associated with the calendar of DateFormat.
650+ */
651+ public TimeZone getTimeZone()
652+ {
653+ return calendar.getTimeZone();
654+ }
655+
656+ /**
657+ * Specify whether or not date/time parsing is to be lenient. With
658+ * lenient parsing, the parser may use heuristics to interpret inputs that
659+ * do not precisely match this object's format. With strict parsing,
660+ * inputs must match this object's format.
661+ *
662+ * <p>This method is equivalent to the following call.
663+ * <blockquote><pre>
664+ * getCalendar().setLenient(lenient)
665+ * </pre></blockquote>
666+ *
667+ * <p>This leniency value is overwritten by a call to {@link
668+ * #setCalendar(java.util.Calendar) setCalendar()}.
669+ *
670+ * @param lenient when {@code true}, parsing is lenient
671+ * @see java.util.Calendar#setLenient(boolean)
672+ */
673+ public void setLenient(boolean lenient)
674+ {
675+ calendar.setLenient(lenient);
676+ }
677+
678+ /**
679+ * Tell whether date/time parsing is to be lenient.
680+ * This method is equivalent to the following call.
681+ * <blockquote><pre>
682+ * getCalendar().isLenient()
683+ * </pre></blockquote>
684+ *
685+ * @return {@code true} if the {@link #calendar} is lenient;
686+ * {@code false} otherwise.
687+ * @see java.util.Calendar#isLenient()
688+ */
689+ public boolean isLenient()
690+ {
691+ return calendar.isLenient();
692+ }
693+
694+ /**
695+ * Overrides hashCode
696+ */
697+ public int hashCode() {
698+ return numberFormat.hashCode();
699+ // just enough fields for a reasonable distribution
700+ }
701+
702+ /**
703+ * Overrides equals
704+ */
705+ public boolean equals(Object obj) {
706+ if (this == obj) return true;
707+ if (obj == null || getClass() != obj.getClass()) return false;
708+ DateFormat other = (DateFormat) obj;
709+ return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
710+ calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
711+ calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
712+ calendar.isLenient() == other.calendar.isLenient() &&
713+ calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
714+ numberFormat.equals(other.numberFormat));
715+ }
716+
717+ /**
718+ * Overrides Cloneable
719+ */
720+ public Object clone()
721+ {
722+ DateFormat other = (DateFormat) super.clone();
723+ other.calendar = (Calendar) calendar.clone();
724+ other.numberFormat = (NumberFormat) numberFormat.clone();
725+ return other;
726+ }
727+
728+ /**
729+ * Creates a DateFormat with the given time and/or date style in the given
730+ * locale.
731+ * @param timeStyle a value from 0 to 3 indicating the time format,
732+ * ignored if flags is 2
733+ * @param dateStyle a value from 0 to 3 indicating the time format,
734+ * ignored if flags is 1
735+ * @param flags either 1 for a time format, 2 for a date format,
736+ * or 3 for a date/time format
737+ * @param loc the locale for the format
738+ */
739+ private static DateFormat get(int timeStyle, int dateStyle,
740+ int flags, Locale loc) {
741+ if ((flags & 1) != 0) {
742+ if (timeStyle < 0 || timeStyle > 3) {
743+ throw new IllegalArgumentException("Illegal time style " + timeStyle);
744+ }
745+ } else {
746+ timeStyle = -1;
747+ }
748+ if ((flags & 2) != 0) {
749+ if (dateStyle < 0 || dateStyle > 3) {
750+ throw new IllegalArgumentException("Illegal date style " + dateStyle);
751+ }
752+ } else {
753+ dateStyle = -1;
754+ }
755+ try {
756+ // Check whether a provider can provide an implementation that's closer
757+ // to the requested locale than what the Java runtime itself can provide.
758+ LocaleServiceProviderPool pool =
759+ LocaleServiceProviderPool.getPool(DateFormatProvider.class);
760+ if (pool.hasProviders()) {
761+ DateFormat providersInstance = pool.getLocalizedObject(
762+ DateFormatGetter.INSTANCE,
763+ loc,
764+ timeStyle,
765+ dateStyle,
766+ flags);
767+ if (providersInstance != null) {
768+ return providersInstance;
769+ }
770+ }
771+
772+ return new SimpleDateFormat(timeStyle, dateStyle, loc);
773+ } catch (MissingResourceException e) {
774+ return new SimpleDateFormat("M/d/yy h:mm a");
775+ }
776+ }
777+
778+ /**
779+ * Create a new date format.
780+ */
781+ protected DateFormat() {}
782+
783+ /**
784+ * Defines constants that are used as attribute keys in the
785+ * <code>AttributedCharacterIterator</code> returned
786+ * from <code>DateFormat.formatToCharacterIterator</code> and as
787+ * field identifiers in <code>FieldPosition</code>.
788+ * <p>
789+ * The class also provides two methods to map
790+ * between its constants and the corresponding Calendar constants.
791+ *
792+ * @since 1.4
793+ * @see java.util.Calendar
794+ */
795+ public static class Field extends Format.Field {
796+
797+ // Proclaim serial compatibility with 1.4 FCS
798+ private static final long serialVersionUID = 7441350119349544720L;
799+
800+ // table of all instances in this class, used by readResolve
801+ private static final Map instanceMap = new HashMap(18);
802+ // Maps from Calendar constant (such as Calendar.ERA) to Field
803+ // constant (such as Field.ERA).
804+ private static final Field[] calendarToFieldMapping =
805+ new Field[Calendar.FIELD_COUNT];
806+
807+ /** Calendar field. */
808+ private int calendarField;
809+
810+ /**
811+ * Returns the <code>Field</code> constant that corresponds to
812+ * the <code>Calendar</code> constant <code>calendarField</code>.
813+ * If there is no direct mapping between the <code>Calendar</code>
814+ * constant and a <code>Field</code>, null is returned.
815+ *
816+ * @throws IllegalArgumentException if <code>calendarField</code> is
817+ * not the value of a <code>Calendar</code> field constant.
818+ * @param calendarField Calendar field constant
819+ * @return Field instance representing calendarField.
820+ * @see java.util.Calendar
821+ */
822+ public static Field ofCalendarField(int calendarField) {
823+ if (calendarField < 0 || calendarField >=
824+ calendarToFieldMapping.length) {
825+ throw new IllegalArgumentException("Unknown Calendar constant "
826+ + calendarField);
827+ }
828+ return calendarToFieldMapping[calendarField];
829+ }
830+
831+ /**
832+ * Creates a <code>Field</code>.
833+ *
834+ * @param name the name of the <code>Field</code>
835+ * @param calendarField the <code>Calendar</code> constant this
836+ * <code>Field</code> corresponds to; any value, even one
837+ * outside the range of legal <code>Calendar</code> values may
838+ * be used, but <code>-1</code> should be used for values
839+ * that don't correspond to legal <code>Calendar</code> values
840+ */
841+ protected Field(String name, int calendarField) {
842+ super(name);
843+ this.calendarField = calendarField;
844+ if (this.getClass() == DateFormat.Field.class) {
845+ instanceMap.put(name, this);
846+ if (calendarField >= 0) {
847+ // assert(calendarField < Calendar.FIELD_COUNT);
848+ calendarToFieldMapping[calendarField] = this;
849+ }
850+ }
851+ }
852+
853+ /**
854+ * Returns the <code>Calendar</code> field associated with this
855+ * attribute. For example, if this represents the hours field of
856+ * a <code>Calendar</code>, this would return
857+ * <code>Calendar.HOUR</code>. If there is no corresponding
858+ * <code>Calendar</code> constant, this will return -1.
859+ *
860+ * @return Calendar constant for this field
861+ * @see java.util.Calendar
862+ */
863+ public int getCalendarField() {
864+ return calendarField;
865+ }
866+
867+ /**
868+ * Resolves instances being deserialized to the predefined constants.
869+ *
870+ * @throws InvalidObjectException if the constant could not be
871+ * resolved.
872+ * @return resolved DateFormat.Field constant
873+ */
874+ protected Object readResolve() throws InvalidObjectException {
875+ if (this.getClass() != DateFormat.Field.class) {
876+ throw new InvalidObjectException("subclass didn't correctly implement readResolve");
877+ }
878+
879+ Object instance = instanceMap.get(getName());
880+ if (instance != null) {
881+ return instance;
882+ } else {
883+ throw new InvalidObjectException("unknown attribute name");
884+ }
885+ }
886+
887+ //
888+ // The constants
889+ //
890+
891+ /**
892+ * Constant identifying the era field.
893+ */
894+ public final static Field ERA = new Field("era", Calendar.ERA);
895+
896+ /**
897+ * Constant identifying the year field.
898+ */
899+ public final static Field YEAR = new Field("year", Calendar.YEAR);
900+
901+ /**
902+ * Constant identifying the month field.
903+ */
904+ public final static Field MONTH = new Field("month", Calendar.MONTH);
905+
906+ /**
907+ * Constant identifying the day of month field.
908+ */
909+ public final static Field DAY_OF_MONTH = new
910+ Field("day of month", Calendar.DAY_OF_MONTH);
911+
912+ /**
913+ * Constant identifying the hour of day field, where the legal values
914+ * are 1 to 24.
915+ */
916+ public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
917+
918+ /**
919+ * Constant identifying the hour of day field, where the legal values
920+ * are 0 to 23.
921+ */
922+ public final static Field HOUR_OF_DAY0 = new
923+ Field("hour of day", Calendar.HOUR_OF_DAY);
924+
925+ /**
926+ * Constant identifying the minute field.
927+ */
928+ public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
929+
930+ /**
931+ * Constant identifying the second field.
932+ */
933+ public final static Field SECOND =new Field("second", Calendar.SECOND);
934+
935+ /**
936+ * Constant identifying the millisecond field.
937+ */
938+ public final static Field MILLISECOND = new
939+ Field("millisecond", Calendar.MILLISECOND);
940+
941+ /**
942+ * Constant identifying the day of week field.
943+ */
944+ public final static Field DAY_OF_WEEK = new
945+ Field("day of week", Calendar.DAY_OF_WEEK);
946+
947+ /**
948+ * Constant identifying the day of year field.
949+ */
950+ public final static Field DAY_OF_YEAR = new
951+ Field("day of year", Calendar.DAY_OF_YEAR);
952+
953+ /**
954+ * Constant identifying the day of week field.
955+ */
956+ public final static Field DAY_OF_WEEK_IN_MONTH =
957+ new Field("day of week in month",
958+ Calendar.DAY_OF_WEEK_IN_MONTH);
959+
960+ /**
961+ * Constant identifying the week of year field.
962+ */
963+ public final static Field WEEK_OF_YEAR = new
964+ Field("week of year", Calendar.WEEK_OF_YEAR);
965+
966+ /**
967+ * Constant identifying the week of month field.
968+ */
969+ public final static Field WEEK_OF_MONTH = new
970+ Field("week of month", Calendar.WEEK_OF_MONTH);
971+
972+ /**
973+ * Constant identifying the time of day indicator
974+ * (e.g. "a.m." or "p.m.") field.
975+ */
976+ public final static Field AM_PM = new
977+ Field("am pm", Calendar.AM_PM);
978+
979+ /**
980+ * Constant identifying the hour field, where the legal values are
981+ * 1 to 12.
982+ */
983+ public final static Field HOUR1 = new Field("hour 1", -1);
984+
985+ /**
986+ * Constant identifying the hour field, where the legal values are
987+ * 0 to 11.
988+ */
989+ public final static Field HOUR0 = new
990+ Field("hour", Calendar.HOUR);
991+
992+ /**
993+ * Constant identifying the time zone field.
994+ */
995+ public final static Field TIME_ZONE = new Field("time zone", -1);
996+ }
997+
998+ /**
999+ * Obtains a DateFormat instance from a DateFormatProvider
1000+ * implementation.
1001+ */
1002+ private static class DateFormatGetter
1003+ implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatProvider, DateFormat> {
1004+ private static final DateFormatGetter INSTANCE = new DateFormatGetter();
1005+
1006+ public DateFormat getObject(DateFormatProvider dateFormatProvider,
1007+ Locale locale,
1008+ String key,
1009+ Object... params) {
1010+ assert params.length == 3;
1011+
1012+ int timeStyle = (Integer)params[0];
1013+ int dateStyle = (Integer)params[1];
1014+ int flags = (Integer)params[2];
1015+
1016+ switch (flags) {
1017+ case 1:
1018+ return dateFormatProvider.getTimeInstance(timeStyle, locale);
1019+ case 2:
1020+ return dateFormatProvider.getDateInstance(dateStyle, locale);
1021+ case 3:
1022+ return dateFormatProvider.getDateTimeInstance(dateStyle, timeStyle, locale);
1023+ default:
1024+ assert false : "should not happen";
1025+ }
1026+
1027+ return null;
1028+ }
1029+ }
1030+}
java/pkg/java/text/DateFormatSymbols$DateFormatSymbolsGetter.class+0−0

Binary file not shown.

java/pkg/java/text/DateFormatSymbols.class+0−0

Binary file not shown.

java/pkg/java/text/DateFormatSymbols.java+794−0
@@ -0,0 +1,794 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.IOException;
42+import java.io.ObjectOutputStream;
43+import java.io.Serializable;
44+import java.lang.ref.SoftReference;
45+import java.text.spi.DateFormatSymbolsProvider;
46+import java.util.Arrays;
47+import java.util.List;
48+import java.util.Locale;
49+import java.util.ResourceBundle;
50+import java.util.TimeZone;
51+import java.util.concurrent.ConcurrentHashMap;
52+import java.util.concurrent.ConcurrentMap;
53+import java.util.spi.LocaleServiceProvider;
54+import sun.util.LocaleServiceProviderPool;
55+import sun.util.TimeZoneNameUtility;
56+import sun.util.calendar.ZoneInfo;
57+import sun.util.resources.LocaleData;
58+
59+/**
60+ * <code>DateFormatSymbols</code> is a public class for encapsulating
61+ * localizable date-time formatting data, such as the names of the
62+ * months, the names of the days of the week, and the time zone data.
63+ * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
64+ * <code>DateFormatSymbols</code> to encapsulate this information.
65+ *
66+ * <p>
67+ * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
68+ * Rather, you are encouraged to create a date-time formatter with the
69+ * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
70+ * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
71+ * These methods automatically create a <code>DateFormatSymbols</code> for
72+ * the formatter so that you don't have to. After the
73+ * formatter is created, you may modify its format pattern using the
74+ * <code>setPattern</code> method. For more information about
75+ * creating formatters using <code>DateFormat</code>'s factory methods,
76+ * see {@link DateFormat}.
77+ *
78+ * <p>
79+ * If you decide to create a date-time formatter with a specific
80+ * format pattern for a specific locale, you can do so with:
81+ * <blockquote>
82+ * <pre>
83+ * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
84+ * </pre>
85+ * </blockquote>
86+ *
87+ * <p>
88+ * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
89+ * a <code>DateFormatSymbols</code> object, feel free to modify the
90+ * date-time formatting data. For instance, you can replace the localized
91+ * date-time format pattern characters with the ones that you feel easy
92+ * to remember. Or you can change the representative cities
93+ * to your favorite ones.
94+ *
95+ * <p>
96+ * New <code>DateFormatSymbols</code> subclasses may be added to support
97+ * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
98+
99+ * @see DateFormat
100+ * @see SimpleDateFormat
101+ * @see java.util.SimpleTimeZone
102+ * @author Chen-Lieh Huang
103+ */
104+public class DateFormatSymbols implements Serializable, Cloneable {
105+
106+ /**
107+ * Construct a DateFormatSymbols object by loading format data from
108+ * resources for the default locale. This constructor can only
109+ * construct instances for the locales supported by the Java
110+ * runtime environment, not for those supported by installed
111+ * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
112+ * implementations. For full locale coverage, use the
113+ * {@link #getInstance(Locale) getInstance} method.
114+ *
115+ * @see #getInstance()
116+ * @exception java.util.MissingResourceException
117+ * if the resources for the default locale cannot be
118+ * found or cannot be loaded.
119+ */
120+ public DateFormatSymbols()
121+ {
122+ initializeData(Locale.getDefault(Locale.Category.FORMAT));
123+ }
124+
125+ /**
126+ * Construct a DateFormatSymbols object by loading format data from
127+ * resources for the given locale. This constructor can only
128+ * construct instances for the locales supported by the Java
129+ * runtime environment, not for those supported by installed
130+ * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
131+ * implementations. For full locale coverage, use the
132+ * {@link #getInstance(Locale) getInstance} method.
133+ *
134+ * @see #getInstance(Locale)
135+ * @exception java.util.MissingResourceException
136+ * if the resources for the specified locale cannot be
137+ * found or cannot be loaded.
138+ */
139+ public DateFormatSymbols(Locale locale)
140+ {
141+ initializeData(locale);
142+ }
143+
144+ /**
145+ * Era strings. For example: "AD" and "BC". An array of 2 strings,
146+ * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
147+ * @serial
148+ */
149+ String eras[] = null;
150+
151+ /**
152+ * Month strings. For example: "January", "February", etc. An array
153+ * of 13 strings (some calendars have 13 months), indexed by
154+ * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
155+ * @serial
156+ */
157+ String months[] = null;
158+
159+ /**
160+ * Short month strings. For example: "Jan", "Feb", etc. An array of
161+ * 13 strings (some calendars have 13 months), indexed by
162+ * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
163+
164+ * @serial
165+ */
166+ String shortMonths[] = null;
167+
168+ /**
169+ * Weekday strings. For example: "Sunday", "Monday", etc. An array
170+ * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
171+ * <code>Calendar.MONDAY</code>, etc.
172+ * The element <code>weekdays[0]</code> is ignored.
173+ * @serial
174+ */
175+ String weekdays[] = null;
176+
177+ /**
178+ * Short weekday strings. For example: "Sun", "Mon", etc. An array
179+ * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
180+ * <code>Calendar.MONDAY</code>, etc.
181+ * The element <code>shortWeekdays[0]</code> is ignored.
182+ * @serial
183+ */
184+ String shortWeekdays[] = null;
185+
186+ /**
187+ * AM and PM strings. For example: "AM" and "PM". An array of
188+ * 2 strings, indexed by <code>Calendar.AM</code> and
189+ * <code>Calendar.PM</code>.
190+ * @serial
191+ */
192+ String ampms[] = null;
193+
194+ /**
195+ * Localized names of time zones in this locale. This is a
196+ * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
197+ * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
198+ * entry containing the localized names for a single <code>TimeZone</code>.
199+ * Each such row contains (with <code>i</code> ranging from
200+ * 0..<em>n</em>-1):
201+ * <ul>
202+ * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
203+ * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
204+ * time</li>
205+ * <li><code>zoneStrings[i][2]</code> - short name of zone in
206+ * standard time</li>
207+ * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
208+ * saving time</li>
209+ * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
210+ * saving time</li>
211+ * </ul>
212+ * The zone ID is <em>not</em> localized; it's one of the valid IDs of
213+ * the {@link java.util.TimeZone TimeZone} class that are not
214+ * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
215+ * All other entries are localized names.
216+ * @see java.util.TimeZone
217+ * @serial
218+ */
219+ String zoneStrings[][] = null;
220+
221+ /**
222+ * Indicates that zoneStrings is set externally with setZoneStrings() method.
223+ */
224+ transient boolean isZoneStringsSet = false;
225+
226+ /**
227+ * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
228+ * All locales use the same these unlocalized pattern characters.
229+ */
230+ static final String patternChars = "GyMdkHmsSEDFwWahKzZYuX";
231+
232+ static final int PATTERN_ERA = 0; // G
233+ static final int PATTERN_YEAR = 1; // y
234+ static final int PATTERN_MONTH = 2; // M
235+ static final int PATTERN_DAY_OF_MONTH = 3; // d
236+ static final int PATTERN_HOUR_OF_DAY1 = 4; // k
237+ static final int PATTERN_HOUR_OF_DAY0 = 5; // H
238+ static final int PATTERN_MINUTE = 6; // m
239+ static final int PATTERN_SECOND = 7; // s
240+ static final int PATTERN_MILLISECOND = 8; // S
241+ static final int PATTERN_DAY_OF_WEEK = 9; // E
242+ static final int PATTERN_DAY_OF_YEAR = 10; // D
243+ static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
244+ static final int PATTERN_WEEK_OF_YEAR = 12; // w
245+ static final int PATTERN_WEEK_OF_MONTH = 13; // W
246+ static final int PATTERN_AM_PM = 14; // a
247+ static final int PATTERN_HOUR1 = 15; // h
248+ static final int PATTERN_HOUR0 = 16; // K
249+ static final int PATTERN_ZONE_NAME = 17; // z
250+ static final int PATTERN_ZONE_VALUE = 18; // Z
251+ static final int PATTERN_WEEK_YEAR = 19; // Y
252+ static final int PATTERN_ISO_DAY_OF_WEEK = 20; // u
253+ static final int PATTERN_ISO_ZONE = 21; // X
254+
255+ /**
256+ * Localized date-time pattern characters. For example, a locale may
257+ * wish to use 'u' rather than 'y' to represent years in its date format
258+ * pattern strings.
259+ * This string must be exactly 18 characters long, with the index of
260+ * the characters described by <code>DateFormat.ERA_FIELD</code>,
261+ * <code>DateFormat.YEAR_FIELD</code>, etc. Thus, if the string were
262+ * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
263+ * @serial
264+ */
265+ String localPatternChars = null;
266+
267+ /**
268+ * The locale which is used for initializing this DateFormatSymbols object.
269+ *
270+ * @since 1.6
271+ * @serial
272+ */
273+ Locale locale = null;
274+
275+ /* use serialVersionUID from JDK 1.1.4 for interoperability */
276+ static final long serialVersionUID = -5987973545549424702L;
277+
278+ /**
279+ * Returns an array of all locales for which the
280+ * <code>getInstance</code> methods of this class can return
281+ * localized instances.
282+ * The returned array represents the union of locales supported by the
283+ * Java runtime and by installed
284+ * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
285+ * implementations. It must contain at least a <code>Locale</code>
286+ * instance equal to {@link java.util.Locale#US Locale.US}.
287+ *
288+ * @return An array of locales for which localized
289+ * <code>DateFormatSymbols</code> instances are available.
290+ * @since 1.6
291+ */
292+ public static Locale[] getAvailableLocales() {
293+ LocaleServiceProviderPool pool=
294+ LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
295+ return pool.getAvailableLocales();
296+ }
297+
298+ /**
299+ * Gets the <code>DateFormatSymbols</code> instance for the default
300+ * locale. This method provides access to <code>DateFormatSymbols</code>
301+ * instances for locales supported by the Java runtime itself as well
302+ * as for those supported by installed
303+ * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
304+ * implementations.
305+ * @return a <code>DateFormatSymbols</code> instance.
306+ * @since 1.6
307+ */
308+ public static final DateFormatSymbols getInstance() {
309+ return getInstance(Locale.getDefault(Locale.Category.FORMAT));
310+ }
311+
312+ /**
313+ * Gets the <code>DateFormatSymbols</code> instance for the specified
314+ * locale. This method provides access to <code>DateFormatSymbols</code>
315+ * instances for locales supported by the Java runtime itself as well
316+ * as for those supported by installed
317+ * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
318+ * implementations.
319+ * @param locale the given locale.
320+ * @return a <code>DateFormatSymbols</code> instance.
321+ * @exception NullPointerException if <code>locale</code> is null
322+ * @since 1.6
323+ */
324+ public static final DateFormatSymbols getInstance(Locale locale) {
325+ DateFormatSymbols dfs = getProviderInstance(locale);
326+ if (dfs != null) {
327+ return dfs;
328+ }
329+ return (DateFormatSymbols) getCachedInstance(locale).clone();
330+ }
331+
332+ /**
333+ * Returns a DateFormatSymbols provided by a provider or found in
334+ * the cache. Note that this method returns a cached instance,
335+ * not its clone. Therefore, the instance should never be given to
336+ * an application.
337+ */
338+ static final DateFormatSymbols getInstanceRef(Locale locale) {
339+ DateFormatSymbols dfs = getProviderInstance(locale);
340+ if (dfs != null) {
341+ return dfs;
342+ }
343+ return getCachedInstance(locale);
344+ }
345+
346+ private static DateFormatSymbols getProviderInstance(Locale locale) {
347+ DateFormatSymbols providersInstance = null;
348+
349+ // Check whether a provider can provide an implementation that's closer
350+ // to the requested locale than what the Java runtime itself can provide.
351+ LocaleServiceProviderPool pool =
352+ LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
353+ if (pool.hasProviders()) {
354+ providersInstance = pool.getLocalizedObject(
355+ DateFormatSymbolsGetter.INSTANCE, locale);
356+ }
357+ return providersInstance;
358+ }
359+
360+ /**
361+ * Returns a cached DateFormatSymbols if it's found in the
362+ * cache. Otherwise, this method returns a newly cached instance
363+ * for the given locale.
364+ */
365+ private static DateFormatSymbols getCachedInstance(Locale locale) {
366+ SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
367+ DateFormatSymbols dfs = null;
368+ if (ref == null || (dfs = ref.get()) == null) {
369+ dfs = new DateFormatSymbols(locale);
370+ ref = new SoftReference<DateFormatSymbols>(dfs);
371+ SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
372+ if (x != null) {
373+ DateFormatSymbols y = x.get();
374+ if (y != null) {
375+ dfs = y;
376+ } else {
377+ // Replace the empty SoftReference with ref.
378+ cachedInstances.put(locale, ref);
379+ }
380+ }
381+ }
382+ return dfs;
383+ }
384+
385+ /**
386+ * Gets era strings. For example: "AD" and "BC".
387+ * @return the era strings.
388+ */
389+ public String[] getEras() {
390+ return Arrays.copyOf(eras, eras.length);
391+ }
392+
393+ /**
394+ * Sets era strings. For example: "AD" and "BC".
395+ * @param newEras the new era strings.
396+ */
397+ public void setEras(String[] newEras) {
398+ eras = Arrays.copyOf(newEras, newEras.length);
399+ }
400+
401+ /**
402+ * Gets month strings. For example: "January", "February", etc.
403+ * @return the month strings.
404+ */
405+ public String[] getMonths() {
406+ return Arrays.copyOf(months, months.length);
407+ }
408+
409+ /**
410+ * Sets month strings. For example: "January", "February", etc.
411+ * @param newMonths the new month strings.
412+ */
413+ public void setMonths(String[] newMonths) {
414+ months = Arrays.copyOf(newMonths, newMonths.length);
415+ }
416+
417+ /**
418+ * Gets short month strings. For example: "Jan", "Feb", etc.
419+ * @return the short month strings.
420+ */
421+ public String[] getShortMonths() {
422+ return Arrays.copyOf(shortMonths, shortMonths.length);
423+ }
424+
425+ /**
426+ * Sets short month strings. For example: "Jan", "Feb", etc.
427+ * @param newShortMonths the new short month strings.
428+ */
429+ public void setShortMonths(String[] newShortMonths) {
430+ shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
431+ }
432+
433+ /**
434+ * Gets weekday strings. For example: "Sunday", "Monday", etc.
435+ * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
436+ * <code>Calendar.MONDAY</code>, etc. to index the result array.
437+ */
438+ public String[] getWeekdays() {
439+ return Arrays.copyOf(weekdays, weekdays.length);
440+ }
441+
442+ /**
443+ * Sets weekday strings. For example: "Sunday", "Monday", etc.
444+ * @param newWeekdays the new weekday strings. The array should
445+ * be indexed by <code>Calendar.SUNDAY</code>,
446+ * <code>Calendar.MONDAY</code>, etc.
447+ */
448+ public void setWeekdays(String[] newWeekdays) {
449+ weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
450+ }
451+
452+ /**
453+ * Gets short weekday strings. For example: "Sun", "Mon", etc.
454+ * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
455+ * <code>Calendar.MONDAY</code>, etc. to index the result array.
456+ */
457+ public String[] getShortWeekdays() {
458+ return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
459+ }
460+
461+ /**
462+ * Sets short weekday strings. For example: "Sun", "Mon", etc.
463+ * @param newShortWeekdays the new short weekday strings. The array should
464+ * be indexed by <code>Calendar.SUNDAY</code>,
465+ * <code>Calendar.MONDAY</code>, etc.
466+ */
467+ public void setShortWeekdays(String[] newShortWeekdays) {
468+ shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
469+ }
470+
471+ /**
472+ * Gets ampm strings. For example: "AM" and "PM".
473+ * @return the ampm strings.
474+ */
475+ public String[] getAmPmStrings() {
476+ return Arrays.copyOf(ampms, ampms.length);
477+ }
478+
479+ /**
480+ * Sets ampm strings. For example: "AM" and "PM".
481+ * @param newAmpms the new ampm strings.
482+ */
483+ public void setAmPmStrings(String[] newAmpms) {
484+ ampms = Arrays.copyOf(newAmpms, newAmpms.length);
485+ }
486+
487+ /**
488+ * Gets time zone strings. Use of this method is discouraged; use
489+ * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
490+ * instead.
491+ * <p>
492+ * The value returned is a
493+ * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
494+ * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
495+ * entry containing the localized names for a single <code>TimeZone</code>.
496+ * Each such row contains (with <code>i</code> ranging from
497+ * 0..<em>n</em>-1):
498+ * <ul>
499+ * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
500+ * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
501+ * time</li>
502+ * <li><code>zoneStrings[i][2]</code> - short name of zone in
503+ * standard time</li>
504+ * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
505+ * saving time</li>
506+ * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
507+ * saving time</li>
508+ * </ul>
509+ * The zone ID is <em>not</em> localized; it's one of the valid IDs of
510+ * the {@link java.util.TimeZone TimeZone} class that are not
511+ * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
512+ * All other entries are localized names. If a zone does not implement
513+ * daylight saving time, the daylight saving time names should not be used.
514+ * <p>
515+ * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
516+ * on this <code>DateFormatSymbols</code> instance, then the strings
517+ * provided by that call are returned. Otherwise, the returned array
518+ * contains names provided by the Java runtime and by installed
519+ * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
520+ * implementations.
521+ *
522+ * @return the time zone strings.
523+ * @see #setZoneStrings(String[][])
524+ */
525+ public String[][] getZoneStrings() {
526+ return getZoneStringsImpl(true);
527+ }
528+
529+ /**
530+ * Sets time zone strings. The argument must be a
531+ * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
532+ * where <em>m</em> is at least 5. Each of the <em>n</em> rows is an
533+ * entry containing the localized names for a single <code>TimeZone</code>.
534+ * Each such row contains (with <code>i</code> ranging from
535+ * 0..<em>n</em>-1):
536+ * <ul>
537+ * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
538+ * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
539+ * time</li>
540+ * <li><code>zoneStrings[i][2]</code> - short name of zone in
541+ * standard time</li>
542+ * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
543+ * saving time</li>
544+ * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
545+ * saving time</li>
546+ * </ul>
547+ * The zone ID is <em>not</em> localized; it's one of the valid IDs of
548+ * the {@link java.util.TimeZone TimeZone} class that are not
549+ * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
550+ * All other entries are localized names.
551+ *
552+ * @param newZoneStrings the new time zone strings.
553+ * @exception IllegalArgumentException if the length of any row in
554+ * <code>newZoneStrings</code> is less than 5
555+ * @exception NullPointerException if <code>newZoneStrings</code> is null
556+ * @see #getZoneStrings()
557+ */
558+ public void setZoneStrings(String[][] newZoneStrings) {
559+ String[][] aCopy = new String[newZoneStrings.length][];
560+ for (int i = 0; i < newZoneStrings.length; ++i) {
561+ int len = newZoneStrings[i].length;
562+ if (len < 5) {
563+ throw new IllegalArgumentException();
564+ }
565+ aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
566+ }
567+ zoneStrings = aCopy;
568+ isZoneStringsSet = true;
569+ }
570+
571+ /**
572+ * Gets localized date-time pattern characters. For example: 'u', 't', etc.
573+ * @return the localized date-time pattern characters.
574+ */
575+ public String getLocalPatternChars() {
576+ return localPatternChars;
577+ }
578+
579+ /**
580+ * Sets localized date-time pattern characters. For example: 'u', 't', etc.
581+ * @param newLocalPatternChars the new localized date-time
582+ * pattern characters.
583+ */
584+ public void setLocalPatternChars(String newLocalPatternChars) {
585+ // Call toString() to throw an NPE in case the argument is null
586+ localPatternChars = newLocalPatternChars.toString();
587+ }
588+
589+ /**
590+ * Overrides Cloneable
591+ */
592+ public Object clone()
593+ {
594+ try
595+ {
596+ DateFormatSymbols other = (DateFormatSymbols)super.clone();
597+ copyMembers(this, other);
598+ return other;
599+ } catch (CloneNotSupportedException e) {
600+ throw new InternalError();
601+ }
602+ }
603+
604+ /**
605+ * Override hashCode.
606+ * Generates a hash code for the DateFormatSymbols object.
607+ */
608+ public int hashCode() {
609+ int hashcode = 0;
610+ String[][] zoneStrings = getZoneStringsWrapper();
611+ for (int index = 0; index < zoneStrings[0].length; ++index)
612+ hashcode ^= zoneStrings[0][index].hashCode();
613+ return hashcode;
614+ }
615+
616+ /**
617+ * Override equals
618+ */
619+ public boolean equals(Object obj)
620+ {
621+ if (this == obj) return true;
622+ if (obj == null || getClass() != obj.getClass()) return false;
623+ DateFormatSymbols that = (DateFormatSymbols) obj;
624+ return (Arrays.equals(eras, that.eras)
625+ && Arrays.equals(months, that.months)
626+ && Arrays.equals(shortMonths, that.shortMonths)
627+ && Arrays.equals(weekdays, that.weekdays)
628+ && Arrays.equals(shortWeekdays, that.shortWeekdays)
629+ && Arrays.equals(ampms, that.ampms)
630+ && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
631+ && ((localPatternChars != null
632+ && localPatternChars.equals(that.localPatternChars))
633+ || (localPatternChars == null
634+ && that.localPatternChars == null)));
635+ }
636+
637+ // =======================privates===============================
638+
639+ /**
640+ * Useful constant for defining time zone offsets.
641+ */
642+ static final int millisPerHour = 60*60*1000;
643+
644+ /**
645+ * Cache to hold DateFormatSymbols instances per Locale.
646+ */
647+ private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
648+ = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
649+
650+ private void initializeData(Locale desiredLocale) {
651+ locale = desiredLocale;
652+
653+ // Copy values of a cached instance if any.
654+ SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
655+ DateFormatSymbols dfs;
656+ if (ref != null && (dfs = ref.get()) != null) {
657+ copyMembers(dfs, this);
658+ return;
659+ }
660+
661+ // Initialize the fields from the ResourceBundle for locale.
662+ ResourceBundle resource = LocaleData.getDateFormatData(locale);
663+
664+ eras = resource.getStringArray("Eras");
665+ months = resource.getStringArray("MonthNames");
666+ shortMonths = resource.getStringArray("MonthAbbreviations");
667+ ampms = resource.getStringArray("AmPmMarkers");
668+ localPatternChars = resource.getString("DateTimePatternChars");
669+
670+ // Day of week names are stored in a 1-based array.
671+ weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
672+ shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
673+ }
674+
675+ private static String[] toOneBasedArray(String[] src) {
676+ int len = src.length;
677+ String[] dst = new String[len + 1];
678+ dst[0] = "";
679+ for (int i = 0; i < len; i++) {
680+ dst[i + 1] = src[i];
681+ }
682+ return dst;
683+ }
684+
685+ /**
686+ * Package private: used by SimpleDateFormat
687+ * Gets the index for the given time zone ID to obtain the time zone
688+ * strings for formatting. The time zone ID is just for programmatic
689+ * lookup. NOT LOCALIZED!!!
690+ * @param ID the given time zone ID.
691+ * @return the index of the given time zone ID. Returns -1 if
692+ * the given time zone ID can't be located in the DateFormatSymbols object.
693+ * @see java.util.SimpleTimeZone
694+ */
695+ final int getZoneIndex(String ID)
696+ {
697+ String[][] zoneStrings = getZoneStringsWrapper();
698+ for (int index=0; index<zoneStrings.length; index++)
699+ {
700+ if (ID.equals(zoneStrings[index][0])) return index;
701+ }
702+
703+ return -1;
704+ }
705+
706+ /**
707+ * Wrapper method to the getZoneStrings(), which is called from inside
708+ * the java.text package and not to mutate the returned arrays, so that
709+ * it does not need to create a defensive copy.
710+ */
711+ final String[][] getZoneStringsWrapper() {
712+ if (isSubclassObject()) {
713+ return getZoneStrings();
714+ } else {
715+ return getZoneStringsImpl(false);
716+ }
717+ }
718+
719+ private final String[][] getZoneStringsImpl(boolean needsCopy) {
720+ if (zoneStrings == null) {
721+ zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
722+ }
723+
724+ if (!needsCopy) {
725+ return zoneStrings;
726+ }
727+
728+ int len = zoneStrings.length;
729+ String[][] aCopy = new String[len][];
730+ for (int i = 0; i < len; i++) {
731+ aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
732+ }
733+ return aCopy;
734+ }
735+
736+ private final boolean isSubclassObject() {
737+ return !getClass().getName().equals("java.text.DateFormatSymbols");
738+ }
739+
740+ /**
741+ * Clones all the data members from the source DateFormatSymbols to
742+ * the target DateFormatSymbols. This is only for subclasses.
743+ * @param src the source DateFormatSymbols.
744+ * @param dst the target DateFormatSymbols.
745+ */
746+ private final void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
747+ {
748+ dst.eras = Arrays.copyOf(src.eras, src.eras.length);
749+ dst.months = Arrays.copyOf(src.months, src.months.length);
750+ dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
751+ dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
752+ dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
753+ dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
754+ if (src.zoneStrings != null) {
755+ dst.zoneStrings = src.getZoneStringsImpl(true);
756+ } else {
757+ dst.zoneStrings = null;
758+ }
759+ dst.localPatternChars = src.localPatternChars;
760+ }
761+
762+ /**
763+ * Write out the default serializable data, after ensuring the
764+ * <code>zoneStrings</code> field is initialized in order to make
765+ * sure the backward compatibility.
766+ *
767+ * @since 1.6
768+ */
769+ private void writeObject(ObjectOutputStream stream) throws IOException {
770+ if (zoneStrings == null) {
771+ zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
772+ }
773+ stream.defaultWriteObject();
774+ }
775+
776+ /**
777+ * Obtains a DateFormatSymbols instance from a DateFormatSymbolsProvider
778+ * implementation.
779+ */
780+ private static class DateFormatSymbolsGetter
781+ implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatSymbolsProvider,
782+ DateFormatSymbols> {
783+ private static final DateFormatSymbolsGetter INSTANCE =
784+ new DateFormatSymbolsGetter();
785+
786+ public DateFormatSymbols getObject(DateFormatSymbolsProvider dateFormatSymbolsProvider,
787+ Locale locale,
788+ String key,
789+ Object... params) {
790+ assert params.length == 0;
791+ return dateFormatSymbolsProvider.getInstance(locale);
792+ }
793+ }
794+}
java/pkg/java/text/DecimalFormat.class+0−0

Binary file not shown.

java/pkg/java/text/DecimalFormat.java+3278−0
@@ -0,0 +1,3278 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.InvalidObjectException;
42+import java.io.IOException;
43+import java.io.ObjectInputStream;
44+import java.math.BigDecimal;
45+import java.math.BigInteger;
46+import java.math.RoundingMode;
47+import java.util.ArrayList;
48+import java.util.Currency;
49+import java.util.Locale;
50+import java.util.ResourceBundle;
51+import java.util.concurrent.ConcurrentHashMap;
52+import java.util.concurrent.ConcurrentMap;
53+import java.util.concurrent.atomic.AtomicInteger;
54+import java.util.concurrent.atomic.AtomicLong;
55+import sun.util.resources.LocaleData;
56+
57+/**
58+ * <code>DecimalFormat</code> is a concrete subclass of
59+ * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
60+ * features designed to make it possible to parse and format numbers in any
61+ * locale, including support for Western, Arabic, and Indic digits. It also
62+ * supports different kinds of numbers, including integers (123), fixed-point
63+ * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
64+ * currency amounts ($123). All of these can be localized.
65+ *
66+ * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
67+ * default locale, call one of <code>NumberFormat</code>'s factory methods, such
68+ * as <code>getInstance()</code>. In general, do not call the
69+ * <code>DecimalFormat</code> constructors directly, since the
70+ * <code>NumberFormat</code> factory methods may return subclasses other than
71+ * <code>DecimalFormat</code>. If you need to customize the format object, do
72+ * something like this:
73+ *
74+ * <blockquote><pre>
75+ * NumberFormat f = NumberFormat.getInstance(loc);
76+ * if (f instanceof DecimalFormat) {
77+ * ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
78+ * }
79+ * </pre></blockquote>
80+ *
81+ * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
82+ * <em>symbols</em>. The pattern may be set directly using
83+ * <code>applyPattern()</code>, or indirectly using the API methods. The
84+ * symbols are stored in a <code>DecimalFormatSymbols</code> object. When using
85+ * the <code>NumberFormat</code> factory methods, the pattern and symbols are
86+ * read from localized <code>ResourceBundle</code>s.
87+ *
88+ * <h4>Patterns</h4>
89+ *
90+ * <code>DecimalFormat</code> patterns have the following syntax:
91+ * <blockquote><pre>
92+ * <i>Pattern:</i>
93+ * <i>PositivePattern</i>
94+ * <i>PositivePattern</i> ; <i>NegativePattern</i>
95+ * <i>PositivePattern:</i>
96+ * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
97+ * <i>NegativePattern:</i>
98+ * <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
99+ * <i>Prefix:</i>
100+ * any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
101+ * <i>Suffix:</i>
102+ * any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
103+ * <i>Number:</i>
104+ * <i>Integer</i> <i>Exponent<sub>opt</sub></i>
105+ * <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
106+ * <i>Integer:</i>
107+ * <i>MinimumInteger</i>
108+ * #
109+ * # <i>Integer</i>
110+ * # , <i>Integer</i>
111+ * <i>MinimumInteger:</i>
112+ * 0
113+ * 0 <i>MinimumInteger</i>
114+ * 0 , <i>MinimumInteger</i>
115+ * <i>Fraction:</i>
116+ * <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
117+ * <i>MinimumFraction:</i>
118+ * 0 <i>MinimumFraction<sub>opt</sub></i>
119+ * <i>OptionalFraction:</i>
120+ * # <i>OptionalFraction<sub>opt</sub></i>
121+ * <i>Exponent:</i>
122+ * E <i>MinimumExponent</i>
123+ * <i>MinimumExponent:</i>
124+ * 0 <i>MinimumExponent<sub>opt</sub></i>
125+ * </pre></blockquote>
126+ *
127+ * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
128+ * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>. Each
129+ * subpattern has a prefix, numeric part, and suffix. The negative subpattern
130+ * is optional; if absent, then the positive subpattern prefixed with the
131+ * localized minus sign (<code>'-'</code> in most locales) is used as the
132+ * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
133+ * <code>"0.00;-0.00"</code>. If there is an explicit negative subpattern, it
134+ * serves only to specify the negative prefix and suffix; the number of digits,
135+ * minimal digits, and other characteristics are all the same as the positive
136+ * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
137+ * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
138+ *
139+ * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
140+ * thousands separators, decimal separators, etc. may be set to arbitrary
141+ * values, and they will appear properly during formatting. However, care must
142+ * be taken that the symbols and strings do not conflict, or parsing will be
143+ * unreliable. For example, either the positive and negative prefixes or the
144+ * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
145+ * to distinguish positive from negative values. (If they are identical, then
146+ * <code>DecimalFormat</code> will behave as if no negative subpattern was
147+ * specified.) Another example is that the decimal separator and thousands
148+ * separator should be distinct characters, or parsing will be impossible.
149+ *
150+ * <p>The grouping separator is commonly used for thousands, but in some
151+ * countries it separates ten-thousands. The grouping size is a constant number
152+ * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
153+ * 1,0000,0000. If you supply a pattern with multiple grouping characters, the
154+ * interval between the last one and the end of the integer is the one that is
155+ * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
156+ * <code>"##,####,####"</code>.
157+ *
158+ * <h4>Special Pattern Characters</h4>
159+ *
160+ * <p>Many characters in a pattern are taken literally; they are matched during
161+ * parsing and output unchanged during formatting. Special characters, on the
162+ * other hand, stand for other characters, strings, or classes of characters.
163+ * They must be quoted, unless noted otherwise, if they are to appear in the
164+ * prefix or suffix as literals.
165+ *
166+ * <p>The characters listed here are used in non-localized patterns. Localized
167+ * patterns use the corresponding characters taken from this formatter's
168+ * <code>DecimalFormatSymbols</code> object instead, and these characters lose
169+ * their special status. Two exceptions are the currency sign and quote, which
170+ * are not localized.
171+ *
172+ * <blockquote>
173+ * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
174+ * location, localized, and meaning.">
175+ * <tr bgcolor="#ccccff">
176+ * <th align=left>Symbol
177+ * <th align=left>Location
178+ * <th align=left>Localized?
179+ * <th align=left>Meaning
180+ * <tr valign=top>
181+ * <td><code>0</code>
182+ * <td>Number
183+ * <td>Yes
184+ * <td>Digit
185+ * <tr valign=top bgcolor="#eeeeff">
186+ * <td><code>#</code>
187+ * <td>Number
188+ * <td>Yes
189+ * <td>Digit, zero shows as absent
190+ * <tr valign=top>
191+ * <td><code>.</code>
192+ * <td>Number
193+ * <td>Yes
194+ * <td>Decimal separator or monetary decimal separator
195+ * <tr valign=top bgcolor="#eeeeff">
196+ * <td><code>-</code>
197+ * <td>Number
198+ * <td>Yes
199+ * <td>Minus sign
200+ * <tr valign=top>
201+ * <td><code>,</code>
202+ * <td>Number
203+ * <td>Yes
204+ * <td>Grouping separator
205+ * <tr valign=top bgcolor="#eeeeff">
206+ * <td><code>E</code>
207+ * <td>Number
208+ * <td>Yes
209+ * <td>Separates mantissa and exponent in scientific notation.
210+ * <em>Need not be quoted in prefix or suffix.</em>
211+ * <tr valign=top>
212+ * <td><code>;</code>
213+ * <td>Subpattern boundary
214+ * <td>Yes
215+ * <td>Separates positive and negative subpatterns
216+ * <tr valign=top bgcolor="#eeeeff">
217+ * <td><code>%</code>
218+ * <td>Prefix or suffix
219+ * <td>Yes
220+ * <td>Multiply by 100 and show as percentage
221+ * <tr valign=top>
222+ * <td><code>&#92;u2030</code>
223+ * <td>Prefix or suffix
224+ * <td>Yes
225+ * <td>Multiply by 1000 and show as per mille value
226+ * <tr valign=top bgcolor="#eeeeff">
227+ * <td><code>&#164;</code> (<code>&#92;u00A4</code>)
228+ * <td>Prefix or suffix
229+ * <td>No
230+ * <td>Currency sign, replaced by currency symbol. If
231+ * doubled, replaced by international currency symbol.
232+ * If present in a pattern, the monetary decimal separator
233+ * is used instead of the decimal separator.
234+ * <tr valign=top>
235+ * <td><code>'</code>
236+ * <td>Prefix or suffix
237+ * <td>No
238+ * <td>Used to quote special characters in a prefix or suffix,
239+ * for example, <code>"'#'#"</code> formats 123 to
240+ * <code>"#123"</code>. To create a single quote
241+ * itself, use two in a row: <code>"# o''clock"</code>.
242+ * </table>
243+ * </blockquote>
244+ *
245+ * <h4>Scientific Notation</h4>
246+ *
247+ * <p>Numbers in scientific notation are expressed as the product of a mantissa
248+ * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
249+ * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
250+ * <code>DecimalFormat</code> can be instructed to format and parse scientific
251+ * notation <em>only via a pattern</em>; there is currently no factory method
252+ * that creates a scientific notation format. In a pattern, the exponent
253+ * character immediately followed by one or more digit characters indicates
254+ * scientific notation. Example: <code>"0.###E0"</code> formats the number
255+ * 1234 as <code>"1.234E3"</code>.
256+ *
257+ * <ul>
258+ * <li>The number of digit characters after the exponent character gives the
259+ * minimum exponent digit count. There is no maximum. Negative exponents are
260+ * formatted using the localized minus sign, <em>not</em> the prefix and suffix
261+ * from the pattern. This allows patterns such as <code>"0.###E0 m/s"</code>.
262+ *
263+ * <li>The minimum and maximum number of integer digits are interpreted
264+ * together:
265+ *
266+ * <ul>
267+ * <li>If the maximum number of integer digits is greater than their minimum number
268+ * and greater than 1, it forces the exponent to be a multiple of the maximum
269+ * number of integer digits, and the minimum number of integer digits to be
270+ * interpreted as 1. The most common use of this is to generate
271+ * <em>engineering notation</em>, in which the exponent is a multiple of three,
272+ * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
273+ * formats to <code>"12.345E3"</code>, and 123456 formats to
274+ * <code>"123.456E3"</code>.
275+ *
276+ * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
277+ * exponent. Example: 0.00123 formatted with <code>"00.###E0"</code> yields
278+ * <code>"12.3E-4"</code>.
279+ * </ul>
280+ *
281+ * <li>The number of significant digits in the mantissa is the sum of the
282+ * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
283+ * unaffected by the maximum integer digits. For example, 12345 formatted with
284+ * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
285+ * the significant digits count to zero. The number of significant digits
286+ * does not affect parsing.
287+ *
288+ * <li>Exponential patterns may not contain grouping separators.
289+ * </ul>
290+ *
291+ * <h4>Rounding</h4>
292+ *
293+ * <code>DecimalFormat</code> provides rounding modes defined in
294+ * {@link java.math.RoundingMode} for formatting. By default, it uses
295+ * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
296+ *
297+ * <h4>Digits</h4>
298+ *
299+ * For formatting, <code>DecimalFormat</code> uses the ten consecutive
300+ * characters starting with the localized zero digit defined in the
301+ * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
302+ * digits as well as all Unicode decimal digits, as defined by
303+ * {@link Character#digit Character.digit}, are recognized.
304+ *
305+ * <h4>Special Values</h4>
306+ *
307+ * <p><code>NaN</code> is formatted as a string, which typically has a single character
308+ * <code>&#92;uFFFD</code>. This string is determined by the
309+ * <code>DecimalFormatSymbols</code> object. This is the only value for which
310+ * the prefixes and suffixes are not used.
311+ *
312+ * <p>Infinity is formatted as a string, which typically has a single character
313+ * <code>&#92;u221E</code>, with the positive or negative prefixes and suffixes
314+ * applied. The infinity string is determined by the
315+ * <code>DecimalFormatSymbols</code> object.
316+ *
317+ * <p>Negative zero (<code>"-0"</code>) parses to
318+ * <ul>
319+ * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
320+ * true,
321+ * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
322+ * and <code>isParseIntegerOnly()</code> is true,
323+ * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
324+ * and <code>isParseIntegerOnly()</code> are false.
325+ * </ul>
326+ *
327+ * <h4><a name="synchronization">Synchronization</a></h4>
328+ *
329+ * <p>
330+ * Decimal formats are generally not synchronized.
331+ * It is recommended to create separate format instances for each thread.
332+ * If multiple threads access a format concurrently, it must be synchronized
333+ * externally.
334+ *
335+ * <h4>Example</h4>
336+ *
337+ * <blockquote><pre>
338+ * <strong>// Print out a number using the localized number, integer, currency,
339+ * // and percent format for each locale</strong>
340+ * Locale[] locales = NumberFormat.getAvailableLocales();
341+ * double myNumber = -1234.56;
342+ * NumberFormat form;
343+ * for (int j=0; j<4; ++j) {
344+ * System.out.println("FORMAT");
345+ * for (int i = 0; i < locales.length; ++i) {
346+ * if (locales[i].getCountry().length() == 0) {
347+ * continue; // Skip language-only locales
348+ * }
349+ * System.out.print(locales[i].getDisplayName());
350+ * switch (j) {
351+ * case 0:
352+ * form = NumberFormat.getInstance(locales[i]); break;
353+ * case 1:
354+ * form = NumberFormat.getIntegerInstance(locales[i]); break;
355+ * case 2:
356+ * form = NumberFormat.getCurrencyInstance(locales[i]); break;
357+ * default:
358+ * form = NumberFormat.getPercentInstance(locales[i]); break;
359+ * }
360+ * if (form instanceof DecimalFormat) {
361+ * System.out.print(": " + ((DecimalFormat) form).toPattern());
362+ * }
363+ * System.out.print(" -> " + form.format(myNumber));
364+ * try {
365+ * System.out.println(" -> " + form.parse(form.format(myNumber)));
366+ * } catch (ParseException e) {}
367+ * }
368+ * }
369+ * </pre></blockquote>
370+ *
371+ * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
372+ * @see NumberFormat
373+ * @see DecimalFormatSymbols
374+ * @see ParsePosition
375+ * @author Mark Davis
376+ * @author Alan Liu
377+ */
378+public class DecimalFormat extends NumberFormat {
379+
380+ /**
381+ * Creates a DecimalFormat using the default pattern and symbols
382+ * for the default locale. This is a convenient way to obtain a
383+ * DecimalFormat when internationalization is not the main concern.
384+ * <p>
385+ * To obtain standard formats for a given locale, use the factory methods
386+ * on NumberFormat such as getNumberInstance. These factories will
387+ * return the most appropriate sub-class of NumberFormat for a given
388+ * locale.
389+ *
390+ * @see java.text.NumberFormat#getInstance
391+ * @see java.text.NumberFormat#getNumberInstance
392+ * @see java.text.NumberFormat#getCurrencyInstance
393+ * @see java.text.NumberFormat#getPercentInstance
394+ */
395+ public DecimalFormat() {
396+ Locale def = Locale.getDefault(Locale.Category.FORMAT);
397+ // try to get the pattern from the cache
398+ String pattern = cachedLocaleData.get(def);
399+ if (pattern == null) { /* cache miss */
400+ // Get the pattern for the default locale.
401+ ResourceBundle rb = LocaleData.getNumberFormatData(def);
402+ String[] all = rb.getStringArray("NumberPatterns");
403+ pattern = all[0];
404+ /* update cache */
405+ cachedLocaleData.putIfAbsent(def, pattern);
406+ }
407+
408+ // Always applyPattern after the symbols are set
409+ this.symbols = new DecimalFormatSymbols(def);
410+ applyPattern(pattern, false);
411+ }
412+
413+
414+ /**
415+ * Creates a DecimalFormat using the given pattern and the symbols
416+ * for the default locale. This is a convenient way to obtain a
417+ * DecimalFormat when internationalization is not the main concern.
418+ * <p>
419+ * To obtain standard formats for a given locale, use the factory methods
420+ * on NumberFormat such as getNumberInstance. These factories will
421+ * return the most appropriate sub-class of NumberFormat for a given
422+ * locale.
423+ *
424+ * @param pattern A non-localized pattern string.
425+ * @exception NullPointerException if <code>pattern</code> is null
426+ * @exception IllegalArgumentException if the given pattern is invalid.
427+ * @see java.text.NumberFormat#getInstance
428+ * @see java.text.NumberFormat#getNumberInstance
429+ * @see java.text.NumberFormat#getCurrencyInstance
430+ * @see java.text.NumberFormat#getPercentInstance
431+ */
432+ public DecimalFormat(String pattern) {
433+ // Always applyPattern after the symbols are set
434+ this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
435+ applyPattern(pattern, false);
436+ }
437+
438+
439+ /**
440+ * Creates a DecimalFormat using the given pattern and symbols.
441+ * Use this constructor when you need to completely customize the
442+ * behavior of the format.
443+ * <p>
444+ * To obtain standard formats for a given
445+ * locale, use the factory methods on NumberFormat such as
446+ * getInstance or getCurrencyInstance. If you need only minor adjustments
447+ * to a standard format, you can modify the format returned by
448+ * a NumberFormat factory method.
449+ *
450+ * @param pattern a non-localized pattern string
451+ * @param symbols the set of symbols to be used
452+ * @exception NullPointerException if any of the given arguments is null
453+ * @exception IllegalArgumentException if the given pattern is invalid
454+ * @see java.text.NumberFormat#getInstance
455+ * @see java.text.NumberFormat#getNumberInstance
456+ * @see java.text.NumberFormat#getCurrencyInstance
457+ * @see java.text.NumberFormat#getPercentInstance
458+ * @see java.text.DecimalFormatSymbols
459+ */
460+ public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
461+ // Always applyPattern after the symbols are set
462+ this.symbols = (DecimalFormatSymbols)symbols.clone();
463+ applyPattern(pattern, false);
464+ }
465+
466+
467+ // Overrides
468+ /**
469+ * Formats a number and appends the resulting text to the given string
470+ * buffer.
471+ * The number can be of any subclass of {@link java.lang.Number}.
472+ * <p>
473+ * This implementation uses the maximum precision permitted.
474+ * @param number the number to format
475+ * @param toAppendTo the <code>StringBuffer</code> to which the formatted
476+ * text is to be appended
477+ * @param pos On input: an alignment field, if desired.
478+ * On output: the offsets of the alignment field.
479+ * @return the value passed in as <code>toAppendTo</code>
480+ * @exception IllegalArgumentException if <code>number</code> is
481+ * null or not an instance of <code>Number</code>.
482+ * @exception NullPointerException if <code>toAppendTo</code> or
483+ * <code>pos</code> is null
484+ * @exception ArithmeticException if rounding is needed with rounding
485+ * mode being set to RoundingMode.UNNECESSARY
486+ * @see java.text.FieldPosition
487+ */
488+ public final StringBuffer format(Object number,
489+ StringBuffer toAppendTo,
490+ FieldPosition pos) {
491+ if (number instanceof Long || number instanceof Integer ||
492+ number instanceof Short || number instanceof Byte ||
493+ number instanceof AtomicInteger ||
494+ number instanceof AtomicLong ||
495+ (number instanceof BigInteger &&
496+ ((BigInteger)number).bitLength () < 64)) {
497+ return format(((Number)number).longValue(), toAppendTo, pos);
498+ } else if (number instanceof BigDecimal) {
499+ return format((BigDecimal)number, toAppendTo, pos);
500+ } else if (number instanceof BigInteger) {
501+ return format((BigInteger)number, toAppendTo, pos);
502+ } else if (number instanceof Number) {
503+ return format(((Number)number).doubleValue(), toAppendTo, pos);
504+ } else {
505+ throw new IllegalArgumentException("Cannot format given Object as a Number");
506+ }
507+ }
508+
509+ /**
510+ * Formats a double to produce a string.
511+ * @param number The double to format
512+ * @param result where the text is to be appended
513+ * @param fieldPosition On input: an alignment field, if desired.
514+ * On output: the offsets of the alignment field.
515+ * @exception ArithmeticException if rounding is needed with rounding
516+ * mode being set to RoundingMode.UNNECESSARY
517+ * @return The formatted number string
518+ * @see java.text.FieldPosition
519+ */
520+ public StringBuffer format(double number, StringBuffer result,
521+ FieldPosition fieldPosition) {
522+ fieldPosition.setBeginIndex(0);
523+ fieldPosition.setEndIndex(0);
524+
525+ return format(number, result, fieldPosition.getFieldDelegate());
526+ }
527+
528+ /**
529+ * Formats a double to produce a string.
530+ * @param number The double to format
531+ * @param result where the text is to be appended
532+ * @param delegate notified of locations of sub fields
533+ * @exception ArithmeticException if rounding is needed with rounding
534+ * mode being set to RoundingMode.UNNECESSARY
535+ * @return The formatted number string
536+ */
537+ private StringBuffer format(double number, StringBuffer result,
538+ FieldDelegate delegate) {
539+ if (Double.isNaN(number) ||
540+ (Double.isInfinite(number) && multiplier == 0)) {
541+ int iFieldStart = result.length();
542+ result.append(symbols.getNaN());
543+ delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
544+ iFieldStart, result.length(), result);
545+ return result;
546+ }
547+
548+ /* Detecting whether a double is negative is easy with the exception of
549+ * the value -0.0. This is a double which has a zero mantissa (and
550+ * exponent), but a negative sign bit. It is semantically distinct from
551+ * a zero with a positive sign bit, and this distinction is important
552+ * to certain kinds of computations. However, it's a little tricky to
553+ * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0). How then, you may
554+ * ask, does it behave distinctly from +0.0? Well, 1/(-0.0) ==
555+ * -Infinity. Proper detection of -0.0 is needed to deal with the
556+ * issues raised by bugs 4106658, 4106667, and 4147706. Liu 7/6/98.
557+ */
558+ boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
559+
560+ if (multiplier != 1) {
561+ number *= multiplier;
562+ }
563+
564+ if (Double.isInfinite(number)) {
565+ if (isNegative) {
566+ append(result, negativePrefix, delegate,
567+ getNegativePrefixFieldPositions(), Field.SIGN);
568+ } else {
569+ append(result, positivePrefix, delegate,
570+ getPositivePrefixFieldPositions(), Field.SIGN);
571+ }
572+
573+ int iFieldStart = result.length();
574+ result.append(symbols.getInfinity());
575+ delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
576+ iFieldStart, result.length(), result);
577+
578+ if (isNegative) {
579+ append(result, negativeSuffix, delegate,
580+ getNegativeSuffixFieldPositions(), Field.SIGN);
581+ } else {
582+ append(result, positiveSuffix, delegate,
583+ getPositiveSuffixFieldPositions(), Field.SIGN);
584+ }
585+
586+ return result;
587+ }
588+
589+ if (isNegative) {
590+ number = -number;
591+ }
592+
593+ // at this point we are guaranteed a nonnegative finite number.
594+ assert(number >= 0 && !Double.isInfinite(number));
595+
596+ synchronized(digitList) {
597+ int maxIntDigits = super.getMaximumIntegerDigits();
598+ int minIntDigits = super.getMinimumIntegerDigits();
599+ int maxFraDigits = super.getMaximumFractionDigits();
600+ int minFraDigits = super.getMinimumFractionDigits();
601+
602+ digitList.set(isNegative, number, useExponentialNotation ?
603+ maxIntDigits + maxFraDigits : maxFraDigits,
604+ !useExponentialNotation);
605+ return subformat(result, delegate, isNegative, false,
606+ maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
607+ }
608+ }
609+
610+ /**
611+ * Format a long to produce a string.
612+ * @param number The long to format
613+ * @param result where the text is to be appended
614+ * @param fieldPosition On input: an alignment field, if desired.
615+ * On output: the offsets of the alignment field.
616+ * @exception ArithmeticException if rounding is needed with rounding
617+ * mode being set to RoundingMode.UNNECESSARY
618+ * @return The formatted number string
619+ * @see java.text.FieldPosition
620+ */
621+ public StringBuffer format(long number, StringBuffer result,
622+ FieldPosition fieldPosition) {
623+ fieldPosition.setBeginIndex(0);
624+ fieldPosition.setEndIndex(0);
625+
626+ return format(number, result, fieldPosition.getFieldDelegate());
627+ }
628+
629+ /**
630+ * Format a long to produce a string.
631+ * @param number The long to format
632+ * @param result where the text is to be appended
633+ * @param delegate notified of locations of sub fields
634+ * @return The formatted number string
635+ * @exception ArithmeticException if rounding is needed with rounding
636+ * mode being set to RoundingMode.UNNECESSARY
637+ * @see java.text.FieldPosition
638+ */
639+ private StringBuffer format(long number, StringBuffer result,
640+ FieldDelegate delegate) {
641+ boolean isNegative = (number < 0);
642+ if (isNegative) {
643+ number = -number;
644+ }
645+
646+ // In general, long values always represent real finite numbers, so
647+ // we don't have to check for +/- Infinity or NaN. However, there
648+ // is one case we have to be careful of: The multiplier can push
649+ // a number near MIN_VALUE or MAX_VALUE outside the legal range. We
650+ // check for this before multiplying, and if it happens we use
651+ // BigInteger instead.
652+ boolean useBigInteger = false;
653+ if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
654+ if (multiplier != 0) {
655+ useBigInteger = true;
656+ }
657+ } else if (multiplier != 1 && multiplier != 0) {
658+ long cutoff = Long.MAX_VALUE / multiplier;
659+ if (cutoff < 0) {
660+ cutoff = -cutoff;
661+ }
662+ useBigInteger = (number > cutoff);
663+ }
664+
665+ if (useBigInteger) {
666+ if (isNegative) {
667+ number = -number;
668+ }
669+ BigInteger bigIntegerValue = BigInteger.valueOf(number);
670+ return format(bigIntegerValue, result, delegate, true);
671+ }
672+
673+ number *= multiplier;
674+ if (number == 0) {
675+ isNegative = false;
676+ } else {
677+ if (multiplier < 0) {
678+ number = -number;
679+ isNegative = !isNegative;
680+ }
681+ }
682+
683+ synchronized(digitList) {
684+ int maxIntDigits = super.getMaximumIntegerDigits();
685+ int minIntDigits = super.getMinimumIntegerDigits();
686+ int maxFraDigits = super.getMaximumFractionDigits();
687+ int minFraDigits = super.getMinimumFractionDigits();
688+
689+ digitList.set(isNegative, number,
690+ useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
691+
692+ return subformat(result, delegate, isNegative, true,
693+ maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
694+ }
695+ }
696+
697+ /**
698+ * Formats a BigDecimal to produce a string.
699+ * @param number The BigDecimal to format
700+ * @param result where the text is to be appended
701+ * @param fieldPosition On input: an alignment field, if desired.
702+ * On output: the offsets of the alignment field.
703+ * @return The formatted number string
704+ * @exception ArithmeticException if rounding is needed with rounding
705+ * mode being set to RoundingMode.UNNECESSARY
706+ * @see java.text.FieldPosition
707+ */
708+ private StringBuffer format(BigDecimal number, StringBuffer result,
709+ FieldPosition fieldPosition) {
710+ fieldPosition.setBeginIndex(0);
711+ fieldPosition.setEndIndex(0);
712+ return format(number, result, fieldPosition.getFieldDelegate());
713+ }
714+
715+ /**
716+ * Formats a BigDecimal to produce a string.
717+ * @param number The BigDecimal to format
718+ * @param result where the text is to be appended
719+ * @param delegate notified of locations of sub fields
720+ * @exception ArithmeticException if rounding is needed with rounding
721+ * mode being set to RoundingMode.UNNECESSARY
722+ * @return The formatted number string
723+ */
724+ private StringBuffer format(BigDecimal number, StringBuffer result,
725+ FieldDelegate delegate) {
726+ if (multiplier != 1) {
727+ number = number.multiply(getBigDecimalMultiplier());
728+ }
729+ boolean isNegative = number.signum() == -1;
730+ if (isNegative) {
731+ number = number.negate();
732+ }
733+
734+ synchronized(digitList) {
735+ int maxIntDigits = getMaximumIntegerDigits();
736+ int minIntDigits = getMinimumIntegerDigits();
737+ int maxFraDigits = getMaximumFractionDigits();
738+ int minFraDigits = getMinimumFractionDigits();
739+ int maximumDigits = maxIntDigits + maxFraDigits;
740+
741+ digitList.set(isNegative, number, useExponentialNotation ?
742+ ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
743+ maxFraDigits, !useExponentialNotation);
744+
745+ return subformat(result, delegate, isNegative, false,
746+ maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
747+ }
748+ }
749+
750+ /**
751+ * Format a BigInteger to produce a string.
752+ * @param number The BigInteger to format
753+ * @param result where the text is to be appended
754+ * @param fieldPosition On input: an alignment field, if desired.
755+ * On output: the offsets of the alignment field.
756+ * @return The formatted number string
757+ * @exception ArithmeticException if rounding is needed with rounding
758+ * mode being set to RoundingMode.UNNECESSARY
759+ * @see java.text.FieldPosition
760+ */
761+ private StringBuffer format(BigInteger number, StringBuffer result,
762+ FieldPosition fieldPosition) {
763+ fieldPosition.setBeginIndex(0);
764+ fieldPosition.setEndIndex(0);
765+
766+ return format(number, result, fieldPosition.getFieldDelegate(), false);
767+ }
768+
769+ /**
770+ * Format a BigInteger to produce a string.
771+ * @param number The BigInteger to format
772+ * @param result where the text is to be appended
773+ * @param delegate notified of locations of sub fields
774+ * @return The formatted number string
775+ * @exception ArithmeticException if rounding is needed with rounding
776+ * mode being set to RoundingMode.UNNECESSARY
777+ * @see java.text.FieldPosition
778+ */
779+ private StringBuffer format(BigInteger number, StringBuffer result,
780+ FieldDelegate delegate, boolean formatLong) {
781+ if (multiplier != 1) {
782+ number = number.multiply(getBigIntegerMultiplier());
783+ }
784+ boolean isNegative = number.signum() == -1;
785+ if (isNegative) {
786+ number = number.negate();
787+ }
788+
789+ synchronized(digitList) {
790+ int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
791+ if (formatLong) {
792+ maxIntDigits = super.getMaximumIntegerDigits();
793+ minIntDigits = super.getMinimumIntegerDigits();
794+ maxFraDigits = super.getMaximumFractionDigits();
795+ minFraDigits = super.getMinimumFractionDigits();
796+ maximumDigits = maxIntDigits + maxFraDigits;
797+ } else {
798+ maxIntDigits = getMaximumIntegerDigits();
799+ minIntDigits = getMinimumIntegerDigits();
800+ maxFraDigits = getMaximumFractionDigits();
801+ minFraDigits = getMinimumFractionDigits();
802+ maximumDigits = maxIntDigits + maxFraDigits;
803+ if (maximumDigits < 0) {
804+ maximumDigits = Integer.MAX_VALUE;
805+ }
806+ }
807+
808+ digitList.set(isNegative, number,
809+ useExponentialNotation ? maximumDigits : 0);
810+
811+ return subformat(result, delegate, isNegative, true,
812+ maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
813+ }
814+ }
815+
816+ /**
817+ * Formats an Object producing an <code>AttributedCharacterIterator</code>.
818+ * You can use the returned <code>AttributedCharacterIterator</code>
819+ * to build the resulting String, as well as to determine information
820+ * about the resulting String.
821+ * <p>
822+ * Each attribute key of the AttributedCharacterIterator will be of type
823+ * <code>NumberFormat.Field</code>, with the attribute value being the
824+ * same as the attribute key.
825+ *
826+ * @exception NullPointerException if obj is null.
827+ * @exception IllegalArgumentException when the Format cannot format the
828+ * given object.
829+ * @exception ArithmeticException if rounding is needed with rounding
830+ * mode being set to RoundingMode.UNNECESSARY
831+ * @param obj The object to format
832+ * @return AttributedCharacterIterator describing the formatted value.
833+ * @since 1.4
834+ */
835+ public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
836+ CharacterIteratorFieldDelegate delegate =
837+ new CharacterIteratorFieldDelegate();
838+ StringBuffer sb = new StringBuffer();
839+
840+ if (obj instanceof Double || obj instanceof Float) {
841+ format(((Number)obj).doubleValue(), sb, delegate);
842+ } else if (obj instanceof Long || obj instanceof Integer ||
843+ obj instanceof Short || obj instanceof Byte ||
844+ obj instanceof AtomicInteger || obj instanceof AtomicLong) {
845+ format(((Number)obj).longValue(), sb, delegate);
846+ } else if (obj instanceof BigDecimal) {
847+ format((BigDecimal)obj, sb, delegate);
848+ } else if (obj instanceof BigInteger) {
849+ format((BigInteger)obj, sb, delegate, false);
850+ } else if (obj == null) {
851+ throw new NullPointerException(
852+ "formatToCharacterIterator must be passed non-null object");
853+ } else {
854+ throw new IllegalArgumentException(
855+ "Cannot format given Object as a Number");
856+ }
857+ return delegate.getIterator(sb.toString());
858+ }
859+
860+ /**
861+ * Complete the formatting of a finite number. On entry, the digitList must
862+ * be filled in with the correct digits.
863+ */
864+ private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
865+ boolean isNegative, boolean isInteger,
866+ int maxIntDigits, int minIntDigits,
867+ int maxFraDigits, int minFraDigits) {
868+ // NOTE: This isn't required anymore because DigitList takes care of this.
869+ //
870+ // // The negative of the exponent represents the number of leading
871+ // // zeros between the decimal and the first non-zero digit, for
872+ // // a value < 0.1 (e.g., for 0.00123, -fExponent == 2). If this
873+ // // is more than the maximum fraction digits, then we have an underflow
874+ // // for the printed representation. We recognize this here and set
875+ // // the DigitList representation to zero in this situation.
876+ //
877+ // if (-digitList.decimalAt >= getMaximumFractionDigits())
878+ // {
879+ // digitList.count = 0;
880+ // }
881+
882+ char zero = symbols.getZeroDigit();
883+ int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
884+ char grouping = symbols.getGroupingSeparator();
885+ char decimal = isCurrencyFormat ?
886+ symbols.getMonetaryDecimalSeparator() :
887+ symbols.getDecimalSeparator();
888+
889+ /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
890+ * format as zero. This allows sensible computations and preserves
891+ * relations such as signum(1/x) = signum(x), where x is +Infinity or
892+ * -Infinity. Prior to this fix, we always formatted zero values as if
893+ * they were positive. Liu 7/6/98.
894+ */
895+ if (digitList.isZero()) {
896+ digitList.decimalAt = 0; // Normalize
897+ }
898+
899+ if (isNegative) {
900+ append(result, negativePrefix, delegate,
901+ getNegativePrefixFieldPositions(), Field.SIGN);
902+ } else {
903+ append(result, positivePrefix, delegate,
904+ getPositivePrefixFieldPositions(), Field.SIGN);
905+ }
906+
907+ if (useExponentialNotation) {
908+ int iFieldStart = result.length();
909+ int iFieldEnd = -1;
910+ int fFieldStart = -1;
911+
912+ // Minimum integer digits are handled in exponential format by
913+ // adjusting the exponent. For example, 0.01234 with 3 minimum
914+ // integer digits is "123.4E-4".
915+
916+ // Maximum integer digits are interpreted as indicating the
917+ // repeating range. This is useful for engineering notation, in
918+ // which the exponent is restricted to a multiple of 3. For
919+ // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
920+ // If maximum integer digits are > 1 and are larger than
921+ // minimum integer digits, then minimum integer digits are
922+ // ignored.
923+ int exponent = digitList.decimalAt;
924+ int repeat = maxIntDigits;
925+ int minimumIntegerDigits = minIntDigits;
926+ if (repeat > 1 && repeat > minIntDigits) {
927+ // A repeating range is defined; adjust to it as follows.
928+ // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
929+ // -3,-4,-5=>-6, etc. This takes into account that the
930+ // exponent we have here is off by one from what we expect;
931+ // it is for the format 0.MMMMMx10^n.
932+ if (exponent >= 1) {
933+ exponent = ((exponent - 1) / repeat) * repeat;
934+ } else {
935+ // integer division rounds towards 0
936+ exponent = ((exponent - repeat) / repeat) * repeat;
937+ }
938+ minimumIntegerDigits = 1;
939+ } else {
940+ // No repeating range is defined; use minimum integer digits.
941+ exponent -= minimumIntegerDigits;
942+ }
943+
944+ // We now output a minimum number of digits, and more if there
945+ // are more digits, up to the maximum number of digits. We
946+ // place the decimal point after the "integer" digits, which
947+ // are the first (decimalAt - exponent) digits.
948+ int minimumDigits = minIntDigits + minFraDigits;
949+ if (minimumDigits < 0) { // overflow?
950+ minimumDigits = Integer.MAX_VALUE;
951+ }
952+
953+ // The number of integer digits is handled specially if the number
954+ // is zero, since then there may be no digits.
955+ int integerDigits = digitList.isZero() ? minimumIntegerDigits :
956+ digitList.decimalAt - exponent;
957+ if (minimumDigits < integerDigits) {
958+ minimumDigits = integerDigits;
959+ }
960+ int totalDigits = digitList.count;
961+ if (minimumDigits > totalDigits) {
962+ totalDigits = minimumDigits;
963+ }
964+ boolean addedDecimalSeparator = false;
965+
966+ for (int i=0; i<totalDigits; ++i) {
967+ if (i == integerDigits) {
968+ // Record field information for caller.
969+ iFieldEnd = result.length();
970+
971+ result.append(decimal);
972+ addedDecimalSeparator = true;
973+
974+ // Record field information for caller.
975+ fFieldStart = result.length();
976+ }
977+ result.append((i < digitList.count) ?
978+ (char)(digitList.digits[i] + zeroDelta) :
979+ zero);
980+ }
981+
982+ if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
983+ // Record field information for caller.
984+ iFieldEnd = result.length();
985+
986+ result.append(decimal);
987+ addedDecimalSeparator = true;
988+
989+ // Record field information for caller.
990+ fFieldStart = result.length();
991+ }
992+
993+ // Record field information
994+ if (iFieldEnd == -1) {
995+ iFieldEnd = result.length();
996+ }
997+ delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
998+ iFieldStart, iFieldEnd, result);
999+ if (addedDecimalSeparator) {
1000+ delegate.formatted(Field.DECIMAL_SEPARATOR,
1001+ Field.DECIMAL_SEPARATOR,
1002+ iFieldEnd, fFieldStart, result);
1003+ }
1004+ if (fFieldStart == -1) {
1005+ fFieldStart = result.length();
1006+ }
1007+ delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
1008+ fFieldStart, result.length(), result);
1009+
1010+ // The exponent is output using the pattern-specified minimum
1011+ // exponent digits. There is no maximum limit to the exponent
1012+ // digits, since truncating the exponent would result in an
1013+ // unacceptable inaccuracy.
1014+ int fieldStart = result.length();
1015+
1016+ result.append(symbols.getExponentSeparator());
1017+
1018+ delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
1019+ fieldStart, result.length(), result);
1020+
1021+ // For zero values, we force the exponent to zero. We
1022+ // must do this here, and not earlier, because the value
1023+ // is used to determine integer digit count above.
1024+ if (digitList.isZero()) {
1025+ exponent = 0;
1026+ }
1027+
1028+ boolean negativeExponent = exponent < 0;
1029+ if (negativeExponent) {
1030+ exponent = -exponent;
1031+ fieldStart = result.length();
1032+ result.append(symbols.getMinusSign());
1033+ delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
1034+ fieldStart, result.length(), result);
1035+ }
1036+ digitList.set(negativeExponent, exponent);
1037+
1038+ int eFieldStart = result.length();
1039+
1040+ for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
1041+ result.append(zero);
1042+ }
1043+ for (int i=0; i<digitList.decimalAt; ++i) {
1044+ result.append((i < digitList.count) ?
1045+ (char)(digitList.digits[i] + zeroDelta) : zero);
1046+ }
1047+ delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
1048+ result.length(), result);
1049+ } else {
1050+ int iFieldStart = result.length();
1051+
1052+ // Output the integer portion. Here 'count' is the total
1053+ // number of integer digits we will display, including both
1054+ // leading zeros required to satisfy getMinimumIntegerDigits,
1055+ // and actual digits present in the number.
1056+ int count = minIntDigits;
1057+ int digitIndex = 0; // Index into digitList.fDigits[]
1058+ if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
1059+ count = digitList.decimalAt;
1060+ }
1061+
1062+ // Handle the case where getMaximumIntegerDigits() is smaller
1063+ // than the real number of integer digits. If this is so, we
1064+ // output the least significant max integer digits. For example,
1065+ // the value 1997 printed with 2 max integer digits is just "97".
1066+ if (count > maxIntDigits) {
1067+ count = maxIntDigits;
1068+ digitIndex = digitList.decimalAt - count;
1069+ }
1070+
1071+ int sizeBeforeIntegerPart = result.length();
1072+ for (int i=count-1; i>=0; --i) {
1073+ if (i < digitList.decimalAt && digitIndex < digitList.count) {
1074+ // Output a real digit
1075+ result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
1076+ } else {
1077+ // Output a leading zero
1078+ result.append(zero);
1079+ }
1080+
1081+ // Output grouping separator if necessary. Don't output a
1082+ // grouping separator if i==0 though; that's at the end of
1083+ // the integer part.
1084+ if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
1085+ (i % groupingSize == 0)) {
1086+ int gStart = result.length();
1087+ result.append(grouping);
1088+ delegate.formatted(Field.GROUPING_SEPARATOR,
1089+ Field.GROUPING_SEPARATOR, gStart,
1090+ result.length(), result);
1091+ }
1092+ }
1093+
1094+ // Determine whether or not there are any printable fractional
1095+ // digits. If we've used up the digits we know there aren't.
1096+ boolean fractionPresent = (minFraDigits > 0) ||
1097+ (!isInteger && digitIndex < digitList.count);
1098+
1099+ // If there is no fraction present, and we haven't printed any
1100+ // integer digits, then print a zero. Otherwise we won't print
1101+ // _any_ digits, and we won't be able to parse this string.
1102+ if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
1103+ result.append(zero);
1104+ }
1105+
1106+ delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
1107+ iFieldStart, result.length(), result);
1108+
1109+ // Output the decimal separator if we always do so.
1110+ int sStart = result.length();
1111+ if (decimalSeparatorAlwaysShown || fractionPresent) {
1112+ result.append(decimal);
1113+ }
1114+
1115+ if (sStart != result.length()) {
1116+ delegate.formatted(Field.DECIMAL_SEPARATOR,
1117+ Field.DECIMAL_SEPARATOR,
1118+ sStart, result.length(), result);
1119+ }
1120+ int fFieldStart = result.length();
1121+
1122+ for (int i=0; i < maxFraDigits; ++i) {
1123+ // Here is where we escape from the loop. We escape if we've
1124+ // output the maximum fraction digits (specified in the for
1125+ // expression above).
1126+ // We also stop when we've output the minimum digits and either:
1127+ // we have an integer, so there is no fractional stuff to
1128+ // display, or we're out of significant digits.
1129+ if (i >= minFraDigits &&
1130+ (isInteger || digitIndex >= digitList.count)) {
1131+ break;
1132+ }
1133+
1134+ // Output leading fractional zeros. These are zeros that come
1135+ // after the decimal but before any significant digits. These
1136+ // are only output if abs(number being formatted) < 1.0.
1137+ if (-1-i > (digitList.decimalAt-1)) {
1138+ result.append(zero);
1139+ continue;
1140+ }
1141+
1142+ // Output a digit, if we have any precision left, or a
1143+ // zero if we don't. We don't want to output noise digits.
1144+ if (!isInteger && digitIndex < digitList.count) {
1145+ result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
1146+ } else {
1147+ result.append(zero);
1148+ }
1149+ }
1150+
1151+ // Record field information for caller.
1152+ delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
1153+ fFieldStart, result.length(), result);
1154+ }
1155+
1156+ if (isNegative) {
1157+ append(result, negativeSuffix, delegate,
1158+ getNegativeSuffixFieldPositions(), Field.SIGN);
1159+ }
1160+ else {
1161+ append(result, positiveSuffix, delegate,
1162+ getPositiveSuffixFieldPositions(), Field.SIGN);
1163+ }
1164+
1165+ return result;
1166+ }
1167+
1168+ /**
1169+ * Appends the String <code>string</code> to <code>result</code>.
1170+ * <code>delegate</code> is notified of all the
1171+ * <code>FieldPosition</code>s in <code>positions</code>.
1172+ * <p>
1173+ * If one of the <code>FieldPosition</code>s in <code>positions</code>
1174+ * identifies a <code>SIGN</code> attribute, it is mapped to
1175+ * <code>signAttribute</code>. This is used
1176+ * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
1177+ * attribute as necessary.
1178+ * <p>
1179+ * This is used by <code>subformat</code> to add the prefix/suffix.
1180+ */
1181+ private void append(StringBuffer result, String string,
1182+ FieldDelegate delegate,
1183+ FieldPosition[] positions,
1184+ Format.Field signAttribute) {
1185+ int start = result.length();
1186+
1187+ if (string.length() > 0) {
1188+ result.append(string);
1189+ for (int counter = 0, max = positions.length; counter < max;
1190+ counter++) {
1191+ FieldPosition fp = positions[counter];
1192+ Format.Field attribute = fp.getFieldAttribute();
1193+
1194+ if (attribute == Field.SIGN) {
1195+ attribute = signAttribute;
1196+ }
1197+ delegate.formatted(attribute, attribute,
1198+ start + fp.getBeginIndex(),
1199+ start + fp.getEndIndex(), result);
1200+ }
1201+ }
1202+ }
1203+
1204+ /**
1205+ * Parses text from a string to produce a <code>Number</code>.
1206+ * <p>
1207+ * The method attempts to parse text starting at the index given by
1208+ * <code>pos</code>.
1209+ * If parsing succeeds, then the index of <code>pos</code> is updated
1210+ * to the index after the last character used (parsing does not necessarily
1211+ * use all characters up to the end of the string), and the parsed
1212+ * number is returned. The updated <code>pos</code> can be used to
1213+ * indicate the starting point for the next call to this method.
1214+ * If an error occurs, then the index of <code>pos</code> is not
1215+ * changed, the error index of <code>pos</code> is set to the index of
1216+ * the character where the error occurred, and null is returned.
1217+ * <p>
1218+ * The subclass returned depends on the value of {@link #isParseBigDecimal}
1219+ * as well as on the string being parsed.
1220+ * <ul>
1221+ * <li>If <code>isParseBigDecimal()</code> is false (the default),
1222+ * most integer values are returned as <code>Long</code>
1223+ * objects, no matter how they are written: <code>"17"</code> and
1224+ * <code>"17.000"</code> both parse to <code>Long(17)</code>.
1225+ * Values that cannot fit into a <code>Long</code> are returned as
1226+ * <code>Double</code>s. This includes values with a fractional part,
1227+ * infinite values, <code>NaN</code>, and the value -0.0.
1228+ * <code>DecimalFormat</code> does <em>not</em> decide whether to
1229+ * return a <code>Double</code> or a <code>Long</code> based on the
1230+ * presence of a decimal separator in the source string. Doing so
1231+ * would prevent integers that overflow the mantissa of a double,
1232+ * such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
1233+ * parsed accurately.
1234+ * <p>
1235+ * Callers may use the <code>Number</code> methods
1236+ * <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
1237+ * the type they want.
1238+ * <li>If <code>isParseBigDecimal()</code> is true, values are returned
1239+ * as <code>BigDecimal</code> objects. The values are the ones
1240+ * constructed by {@link java.math.BigDecimal#BigDecimal(String)}
1241+ * for corresponding strings in locale-independent format. The
1242+ * special cases negative and positive infinity and NaN are returned
1243+ * as <code>Double</code> instances holding the values of the
1244+ * corresponding <code>Double</code> constants.
1245+ * </ul>
1246+ * <p>
1247+ * <code>DecimalFormat</code> parses all Unicode characters that represent
1248+ * decimal digits, as defined by <code>Character.digit()</code>. In
1249+ * addition, <code>DecimalFormat</code> also recognizes as digits the ten
1250+ * consecutive characters starting with the localized zero digit defined in
1251+ * the <code>DecimalFormatSymbols</code> object.
1252+ *
1253+ * @param text the string to be parsed
1254+ * @param pos A <code>ParsePosition</code> object with index and error
1255+ * index information as described above.
1256+ * @return the parsed value, or <code>null</code> if the parse fails
1257+ * @exception NullPointerException if <code>text</code> or
1258+ * <code>pos</code> is null.
1259+ */
1260+ public Number parse(String text, ParsePosition pos) {
1261+ // special case NaN
1262+ if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
1263+ pos.index = pos.index + symbols.getNaN().length();
1264+ return new Double(Double.NaN);
1265+ }
1266+
1267+ boolean[] status = new boolean[STATUS_LENGTH];
1268+ if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
1269+ return null;
1270+ }
1271+
1272+ // special case INFINITY
1273+ if (status[STATUS_INFINITE]) {
1274+ if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
1275+ return new Double(Double.POSITIVE_INFINITY);
1276+ } else {
1277+ return new Double(Double.NEGATIVE_INFINITY);
1278+ }
1279+ }
1280+
1281+ if (multiplier == 0) {
1282+ if (digitList.isZero()) {
1283+ return new Double(Double.NaN);
1284+ } else if (status[STATUS_POSITIVE]) {
1285+ return new Double(Double.POSITIVE_INFINITY);
1286+ } else {
1287+ return new Double(Double.NEGATIVE_INFINITY);
1288+ }
1289+ }
1290+
1291+ if (isParseBigDecimal()) {
1292+ BigDecimal bigDecimalResult = digitList.getBigDecimal();
1293+
1294+ if (multiplier != 1) {
1295+ try {
1296+ bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
1297+ }
1298+ catch (ArithmeticException e) { // non-terminating decimal expansion
1299+ bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
1300+ }
1301+ }
1302+
1303+ if (!status[STATUS_POSITIVE]) {
1304+ bigDecimalResult = bigDecimalResult.negate();
1305+ }
1306+ return bigDecimalResult;
1307+ } else {
1308+ boolean gotDouble = true;
1309+ boolean gotLongMinimum = false;
1310+ double doubleResult = 0.0;
1311+ long longResult = 0;
1312+
1313+ // Finally, have DigitList parse the digits into a value.
1314+ if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
1315+ gotDouble = false;
1316+ longResult = digitList.getLong();
1317+ if (longResult < 0) { // got Long.MIN_VALUE
1318+ gotLongMinimum = true;
1319+ }
1320+ } else {
1321+ doubleResult = digitList.getDouble();
1322+ }
1323+
1324+ // Divide by multiplier. We have to be careful here not to do
1325+ // unneeded conversions between double and long.
1326+ if (multiplier != 1) {
1327+ if (gotDouble) {
1328+ doubleResult /= multiplier;
1329+ } else {
1330+ // Avoid converting to double if we can
1331+ if (longResult % multiplier == 0) {
1332+ longResult /= multiplier;
1333+ } else {
1334+ doubleResult = ((double)longResult) / multiplier;
1335+ gotDouble = true;
1336+ }
1337+ }
1338+ }
1339+
1340+ if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
1341+ doubleResult = -doubleResult;
1342+ longResult = -longResult;
1343+ }
1344+
1345+ // At this point, if we divided the result by the multiplier, the
1346+ // result may fit into a long. We check for this case and return
1347+ // a long if possible.
1348+ // We must do this AFTER applying the negative (if appropriate)
1349+ // in order to handle the case of LONG_MIN; otherwise, if we do
1350+ // this with a positive value -LONG_MIN, the double is > 0, but
1351+ // the long is < 0. We also must retain a double in the case of
1352+ // -0.0, which will compare as == to a long 0 cast to a double
1353+ // (bug 4162852).
1354+ if (multiplier != 1 && gotDouble) {
1355+ longResult = (long)doubleResult;
1356+ gotDouble = ((doubleResult != (double)longResult) ||
1357+ (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
1358+ !isParseIntegerOnly();
1359+ }
1360+
1361+ return gotDouble ?
1362+ (Number)new Double(doubleResult) : (Number)new Long(longResult);
1363+ }
1364+ }
1365+
1366+ /**
1367+ * Return a BigInteger multiplier.
1368+ */
1369+ private BigInteger getBigIntegerMultiplier() {
1370+ if (bigIntegerMultiplier == null) {
1371+ bigIntegerMultiplier = BigInteger.valueOf(multiplier);
1372+ }
1373+ return bigIntegerMultiplier;
1374+ }
1375+ private transient BigInteger bigIntegerMultiplier;
1376+
1377+ /**
1378+ * Return a BigDecimal multiplier.
1379+ */
1380+ private BigDecimal getBigDecimalMultiplier() {
1381+ if (bigDecimalMultiplier == null) {
1382+ bigDecimalMultiplier = new BigDecimal(multiplier);
1383+ }
1384+ return bigDecimalMultiplier;
1385+ }
1386+ private transient BigDecimal bigDecimalMultiplier;
1387+
1388+ private static final int STATUS_INFINITE = 0;
1389+ private static final int STATUS_POSITIVE = 1;
1390+ private static final int STATUS_LENGTH = 2;
1391+
1392+ /**
1393+ * Parse the given text into a number. The text is parsed beginning at
1394+ * parsePosition, until an unparseable character is seen.
1395+ * @param text The string to parse.
1396+ * @param parsePosition The position at which to being parsing. Upon
1397+ * return, the first unparseable character.
1398+ * @param digits The DigitList to set to the parsed value.
1399+ * @param isExponent If true, parse an exponent. This means no
1400+ * infinite values and integer only.
1401+ * @param status Upon return contains boolean status flags indicating
1402+ * whether the value was infinite and whether it was positive.
1403+ */
1404+ private final boolean subparse(String text, ParsePosition parsePosition,
1405+ String positivePrefix, String negativePrefix,
1406+ DigitList digits, boolean isExponent,
1407+ boolean status[]) {
1408+ int position = parsePosition.index;
1409+ int oldStart = parsePosition.index;
1410+ int backup;
1411+ boolean gotPositive, gotNegative;
1412+
1413+ // check for positivePrefix; take longest
1414+ gotPositive = text.regionMatches(position, positivePrefix, 0,
1415+ positivePrefix.length());
1416+ gotNegative = text.regionMatches(position, negativePrefix, 0,
1417+ negativePrefix.length());
1418+
1419+ if (gotPositive && gotNegative) {
1420+ if (positivePrefix.length() > negativePrefix.length()) {
1421+ gotNegative = false;
1422+ } else if (positivePrefix.length() < negativePrefix.length()) {
1423+ gotPositive = false;
1424+ }
1425+ }
1426+
1427+ if (gotPositive) {
1428+ position += positivePrefix.length();
1429+ } else if (gotNegative) {
1430+ position += negativePrefix.length();
1431+ } else {
1432+ parsePosition.errorIndex = position;
1433+ return false;
1434+ }
1435+
1436+ // process digits or Inf, find decimal position
1437+ status[STATUS_INFINITE] = false;
1438+ if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
1439+ symbols.getInfinity().length())) {
1440+ position += symbols.getInfinity().length();
1441+ status[STATUS_INFINITE] = true;
1442+ } else {
1443+ // We now have a string of digits, possibly with grouping symbols,
1444+ // and decimal points. We want to process these into a DigitList.
1445+ // We don't want to put a bunch of leading zeros into the DigitList
1446+ // though, so we keep track of the location of the decimal point,
1447+ // put only significant digits into the DigitList, and adjust the
1448+ // exponent as needed.
1449+
1450+ digits.decimalAt = digits.count = 0;
1451+ char zero = symbols.getZeroDigit();
1452+ char decimal = isCurrencyFormat ?
1453+ symbols.getMonetaryDecimalSeparator() :
1454+ symbols.getDecimalSeparator();
1455+ char grouping = symbols.getGroupingSeparator();
1456+ String exponentString = symbols.getExponentSeparator();
1457+ boolean sawDecimal = false;
1458+ boolean sawExponent = false;
1459+ boolean sawDigit = false;
1460+ int exponent = 0; // Set to the exponent value, if any
1461+
1462+ // We have to track digitCount ourselves, because digits.count will
1463+ // pin when the maximum allowable digits is reached.
1464+ int digitCount = 0;
1465+
1466+ backup = -1;
1467+ for (; position < text.length(); ++position) {
1468+ char ch = text.charAt(position);
1469+
1470+ /* We recognize all digit ranges, not only the Latin digit range
1471+ * '0'..'9'. We do so by using the Character.digit() method,
1472+ * which converts a valid Unicode digit to the range 0..9.
1473+ *
1474+ * The character 'ch' may be a digit. If so, place its value
1475+ * from 0 to 9 in 'digit'. First try using the locale digit,
1476+ * which may or MAY NOT be a standard Unicode digit range. If
1477+ * this fails, try using the standard Unicode digit ranges by
1478+ * calling Character.digit(). If this also fails, digit will
1479+ * have a value outside the range 0..9.
1480+ */
1481+ int digit = ch - zero;
1482+ if (digit < 0 || digit > 9) {
1483+ digit = Character.digit(ch, 10);
1484+ }
1485+
1486+ if (digit == 0) {
1487+ // Cancel out backup setting (see grouping handler below)
1488+ backup = -1; // Do this BEFORE continue statement below!!!
1489+ sawDigit = true;
1490+
1491+ // Handle leading zeros
1492+ if (digits.count == 0) {
1493+ // Ignore leading zeros in integer part of number.
1494+ if (!sawDecimal) {
1495+ continue;
1496+ }
1497+
1498+ // If we have seen the decimal, but no significant
1499+ // digits yet, then we account for leading zeros by
1500+ // decrementing the digits.decimalAt into negative
1501+ // values.
1502+ --digits.decimalAt;
1503+ } else {
1504+ ++digitCount;
1505+ digits.append((char)(digit + '0'));
1506+ }
1507+ } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
1508+ sawDigit = true;
1509+ ++digitCount;
1510+ digits.append((char)(digit + '0'));
1511+
1512+ // Cancel out backup setting (see grouping handler below)
1513+ backup = -1;
1514+ } else if (!isExponent && ch == decimal) {
1515+ // If we're only parsing integers, or if we ALREADY saw the
1516+ // decimal, then don't parse this one.
1517+ if (isParseIntegerOnly() || sawDecimal) {
1518+ break;
1519+ }
1520+ digits.decimalAt = digitCount; // Not digits.count!
1521+ sawDecimal = true;
1522+ } else if (!isExponent && ch == grouping && isGroupingUsed()) {
1523+ if (sawDecimal) {
1524+ break;
1525+ }
1526+ // Ignore grouping characters, if we are using them, but
1527+ // require that they be followed by a digit. Otherwise
1528+ // we backup and reprocess them.
1529+ backup = position;
1530+ } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
1531+ && !sawExponent) {
1532+ // Process the exponent by recursively calling this method.
1533+ ParsePosition pos = new ParsePosition(position + exponentString.length());
1534+ boolean[] stat = new boolean[STATUS_LENGTH];
1535+ DigitList exponentDigits = new DigitList();
1536+
1537+ if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
1538+ exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
1539+ position = pos.index; // Advance past the exponent
1540+ exponent = (int)exponentDigits.getLong();
1541+ if (!stat[STATUS_POSITIVE]) {
1542+ exponent = -exponent;
1543+ }
1544+ sawExponent = true;
1545+ }
1546+ break; // Whether we fail or succeed, we exit this loop
1547+ }
1548+ else {
1549+ break;
1550+ }
1551+ }
1552+
1553+ if (backup != -1) {
1554+ position = backup;
1555+ }
1556+
1557+ // If there was no decimal point we have an integer
1558+ if (!sawDecimal) {
1559+ digits.decimalAt = digitCount; // Not digits.count!
1560+ }
1561+
1562+ // Adjust for exponent, if any
1563+ digits.decimalAt += exponent;
1564+
1565+ // If none of the text string was recognized. For example, parse
1566+ // "x" with pattern "#0.00" (return index and error index both 0)
1567+ // parse "$" with pattern "$#0.00". (return index 0 and error
1568+ // index 1).
1569+ if (!sawDigit && digitCount == 0) {
1570+ parsePosition.index = oldStart;
1571+ parsePosition.errorIndex = oldStart;
1572+ return false;
1573+ }
1574+ }
1575+
1576+ // check for suffix
1577+ if (!isExponent) {
1578+ if (gotPositive) {
1579+ gotPositive = text.regionMatches(position,positiveSuffix,0,
1580+ positiveSuffix.length());
1581+ }
1582+ if (gotNegative) {
1583+ gotNegative = text.regionMatches(position,negativeSuffix,0,
1584+ negativeSuffix.length());
1585+ }
1586+
1587+ // if both match, take longest
1588+ if (gotPositive && gotNegative) {
1589+ if (positiveSuffix.length() > negativeSuffix.length()) {
1590+ gotNegative = false;
1591+ } else if (positiveSuffix.length() < negativeSuffix.length()) {
1592+ gotPositive = false;
1593+ }
1594+ }
1595+
1596+ // fail if neither or both
1597+ if (gotPositive == gotNegative) {
1598+ parsePosition.errorIndex = position;
1599+ return false;
1600+ }
1601+
1602+ parsePosition.index = position +
1603+ (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
1604+ } else {
1605+ parsePosition.index = position;
1606+ }
1607+
1608+ status[STATUS_POSITIVE] = gotPositive;
1609+ if (parsePosition.index == oldStart) {
1610+ parsePosition.errorIndex = position;
1611+ return false;
1612+ }
1613+ return true;
1614+ }
1615+
1616+ /**
1617+ * Returns a copy of the decimal format symbols, which is generally not
1618+ * changed by the programmer or user.
1619+ * @return a copy of the desired DecimalFormatSymbols
1620+ * @see java.text.DecimalFormatSymbols
1621+ */
1622+ public DecimalFormatSymbols getDecimalFormatSymbols() {
1623+ try {
1624+ // don't allow multiple references
1625+ return (DecimalFormatSymbols) symbols.clone();
1626+ } catch (Exception foo) {
1627+ return null; // should never happen
1628+ }
1629+ }
1630+
1631+
1632+ /**
1633+ * Sets the decimal format symbols, which is generally not changed
1634+ * by the programmer or user.
1635+ * @param newSymbols desired DecimalFormatSymbols
1636+ * @see java.text.DecimalFormatSymbols
1637+ */
1638+ public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
1639+ try {
1640+ // don't allow multiple references
1641+ symbols = (DecimalFormatSymbols) newSymbols.clone();
1642+ expandAffixes();
1643+ } catch (Exception foo) {
1644+ // should never happen
1645+ }
1646+ }
1647+
1648+ /**
1649+ * Get the positive prefix.
1650+ * <P>Examples: +123, $123, sFr123
1651+ */
1652+ public String getPositivePrefix () {
1653+ return positivePrefix;
1654+ }
1655+
1656+ /**
1657+ * Set the positive prefix.
1658+ * <P>Examples: +123, $123, sFr123
1659+ */
1660+ public void setPositivePrefix (String newValue) {
1661+ positivePrefix = newValue;
1662+ posPrefixPattern = null;
1663+ positivePrefixFieldPositions = null;
1664+ }
1665+
1666+ /**
1667+ * Returns the FieldPositions of the fields in the prefix used for
1668+ * positive numbers. This is not used if the user has explicitly set
1669+ * a positive prefix via <code>setPositivePrefix</code>. This is
1670+ * lazily created.
1671+ *
1672+ * @return FieldPositions in positive prefix
1673+ */
1674+ private FieldPosition[] getPositivePrefixFieldPositions() {
1675+ if (positivePrefixFieldPositions == null) {
1676+ if (posPrefixPattern != null) {
1677+ positivePrefixFieldPositions = expandAffix(posPrefixPattern);
1678+ }
1679+ else {
1680+ positivePrefixFieldPositions = EmptyFieldPositionArray;
1681+ }
1682+ }
1683+ return positivePrefixFieldPositions;
1684+ }
1685+
1686+ /**
1687+ * Get the negative prefix.
1688+ * <P>Examples: -123, ($123) (with negative suffix), sFr-123
1689+ */
1690+ public String getNegativePrefix () {
1691+ return negativePrefix;
1692+ }
1693+
1694+ /**
1695+ * Set the negative prefix.
1696+ * <P>Examples: -123, ($123) (with negative suffix), sFr-123
1697+ */
1698+ public void setNegativePrefix (String newValue) {
1699+ negativePrefix = newValue;
1700+ negPrefixPattern = null;
1701+ }
1702+
1703+ /**
1704+ * Returns the FieldPositions of the fields in the prefix used for
1705+ * negative numbers. This is not used if the user has explicitly set
1706+ * a negative prefix via <code>setNegativePrefix</code>. This is
1707+ * lazily created.
1708+ *
1709+ * @return FieldPositions in positive prefix
1710+ */
1711+ private FieldPosition[] getNegativePrefixFieldPositions() {
1712+ if (negativePrefixFieldPositions == null) {
1713+ if (negPrefixPattern != null) {
1714+ negativePrefixFieldPositions = expandAffix(negPrefixPattern);
1715+ }
1716+ else {
1717+ negativePrefixFieldPositions = EmptyFieldPositionArray;
1718+ }
1719+ }
1720+ return negativePrefixFieldPositions;
1721+ }
1722+
1723+ /**
1724+ * Get the positive suffix.
1725+ * <P>Example: 123%
1726+ */
1727+ public String getPositiveSuffix () {
1728+ return positiveSuffix;
1729+ }
1730+
1731+ /**
1732+ * Set the positive suffix.
1733+ * <P>Example: 123%
1734+ */
1735+ public void setPositiveSuffix (String newValue) {
1736+ positiveSuffix = newValue;
1737+ posSuffixPattern = null;
1738+ }
1739+
1740+ /**
1741+ * Returns the FieldPositions of the fields in the suffix used for
1742+ * positive numbers. This is not used if the user has explicitly set
1743+ * a positive suffix via <code>setPositiveSuffix</code>. This is
1744+ * lazily created.
1745+ *
1746+ * @return FieldPositions in positive prefix
1747+ */
1748+ private FieldPosition[] getPositiveSuffixFieldPositions() {
1749+ if (positiveSuffixFieldPositions == null) {
1750+ if (posSuffixPattern != null) {
1751+ positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
1752+ }
1753+ else {
1754+ positiveSuffixFieldPositions = EmptyFieldPositionArray;
1755+ }
1756+ }
1757+ return positiveSuffixFieldPositions;
1758+ }
1759+
1760+ /**
1761+ * Get the negative suffix.
1762+ * <P>Examples: -123%, ($123) (with positive suffixes)
1763+ */
1764+ public String getNegativeSuffix () {
1765+ return negativeSuffix;
1766+ }
1767+
1768+ /**
1769+ * Set the negative suffix.
1770+ * <P>Examples: 123%
1771+ */
1772+ public void setNegativeSuffix (String newValue) {
1773+ negativeSuffix = newValue;
1774+ negSuffixPattern = null;
1775+ }
1776+
1777+ /**
1778+ * Returns the FieldPositions of the fields in the suffix used for
1779+ * negative numbers. This is not used if the user has explicitly set
1780+ * a negative suffix via <code>setNegativeSuffix</code>. This is
1781+ * lazily created.
1782+ *
1783+ * @return FieldPositions in positive prefix
1784+ */
1785+ private FieldPosition[] getNegativeSuffixFieldPositions() {
1786+ if (negativeSuffixFieldPositions == null) {
1787+ if (negSuffixPattern != null) {
1788+ negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
1789+ }
1790+ else {
1791+ negativeSuffixFieldPositions = EmptyFieldPositionArray;
1792+ }
1793+ }
1794+ return negativeSuffixFieldPositions;
1795+ }
1796+
1797+ /**
1798+ * Gets the multiplier for use in percent, per mille, and similar
1799+ * formats.
1800+ *
1801+ * @see #setMultiplier(int)
1802+ */
1803+ public int getMultiplier () {
1804+ return multiplier;
1805+ }
1806+
1807+ /**
1808+ * Sets the multiplier for use in percent, per mille, and similar
1809+ * formats.
1810+ * For a percent format, set the multiplier to 100 and the suffixes to
1811+ * have '%' (for Arabic, use the Arabic percent sign).
1812+ * For a per mille format, set the multiplier to 1000 and the suffixes to
1813+ * have '&#92;u2030'.
1814+ *
1815+ * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
1816+ * "123" is parsed into 1.23.
1817+ *
1818+ * @see #getMultiplier
1819+ */
1820+ public void setMultiplier (int newValue) {
1821+ multiplier = newValue;
1822+ bigDecimalMultiplier = null;
1823+ bigIntegerMultiplier = null;
1824+ }
1825+
1826+ /**
1827+ * Return the grouping size. Grouping size is the number of digits between
1828+ * grouping separators in the integer portion of a number. For example,
1829+ * in the number "123,456.78", the grouping size is 3.
1830+ * @see #setGroupingSize
1831+ * @see java.text.NumberFormat#isGroupingUsed
1832+ * @see java.text.DecimalFormatSymbols#getGroupingSeparator
1833+ */
1834+ public int getGroupingSize () {
1835+ return groupingSize;
1836+ }
1837+
1838+ /**
1839+ * Set the grouping size. Grouping size is the number of digits between
1840+ * grouping separators in the integer portion of a number. For example,
1841+ * in the number "123,456.78", the grouping size is 3.
1842+ * <br>
1843+ * The value passed in is converted to a byte, which may lose information.
1844+ * @see #getGroupingSize
1845+ * @see java.text.NumberFormat#setGroupingUsed
1846+ * @see java.text.DecimalFormatSymbols#setGroupingSeparator
1847+ */
1848+ public void setGroupingSize (int newValue) {
1849+ groupingSize = (byte)newValue;
1850+ }
1851+
1852+ /**
1853+ * Allows you to get the behavior of the decimal separator with integers.
1854+ * (The decimal separator will always appear with decimals.)
1855+ * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
1856+ */
1857+ public boolean isDecimalSeparatorAlwaysShown() {
1858+ return decimalSeparatorAlwaysShown;
1859+ }
1860+
1861+ /**
1862+ * Allows you to set the behavior of the decimal separator with integers.
1863+ * (The decimal separator will always appear with decimals.)
1864+ * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
1865+ */
1866+ public void setDecimalSeparatorAlwaysShown(boolean newValue) {
1867+ decimalSeparatorAlwaysShown = newValue;
1868+ }
1869+
1870+ /**
1871+ * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
1872+ * method returns <code>BigDecimal</code>. The default value is false.
1873+ * @see #setParseBigDecimal
1874+ * @since 1.5
1875+ */
1876+ public boolean isParseBigDecimal() {
1877+ return parseBigDecimal;
1878+ }
1879+
1880+ /**
1881+ * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
1882+ * method returns <code>BigDecimal</code>.
1883+ * @see #isParseBigDecimal
1884+ * @since 1.5
1885+ */
1886+ public void setParseBigDecimal(boolean newValue) {
1887+ parseBigDecimal = newValue;
1888+ }
1889+
1890+ /**
1891+ * Standard override; no change in semantics.
1892+ */
1893+ public Object clone() {
1894+ try {
1895+ DecimalFormat other = (DecimalFormat) super.clone();
1896+ other.symbols = (DecimalFormatSymbols) symbols.clone();
1897+ other.digitList = (DigitList) digitList.clone();
1898+ return other;
1899+ } catch (Exception e) {
1900+ throw new InternalError();
1901+ }
1902+ }
1903+
1904+ /**
1905+ * Overrides equals
1906+ */
1907+ public boolean equals(Object obj)
1908+ {
1909+ if (obj == null) return false;
1910+ if (!super.equals(obj)) return false; // super does class check
1911+ DecimalFormat other = (DecimalFormat) obj;
1912+ return ((posPrefixPattern == other.posPrefixPattern &&
1913+ positivePrefix.equals(other.positivePrefix))
1914+ || (posPrefixPattern != null &&
1915+ posPrefixPattern.equals(other.posPrefixPattern)))
1916+ && ((posSuffixPattern == other.posSuffixPattern &&
1917+ positiveSuffix.equals(other.positiveSuffix))
1918+ || (posSuffixPattern != null &&
1919+ posSuffixPattern.equals(other.posSuffixPattern)))
1920+ && ((negPrefixPattern == other.negPrefixPattern &&
1921+ negativePrefix.equals(other.negativePrefix))
1922+ || (negPrefixPattern != null &&
1923+ negPrefixPattern.equals(other.negPrefixPattern)))
1924+ && ((negSuffixPattern == other.negSuffixPattern &&
1925+ negativeSuffix.equals(other.negativeSuffix))
1926+ || (negSuffixPattern != null &&
1927+ negSuffixPattern.equals(other.negSuffixPattern)))
1928+ && multiplier == other.multiplier
1929+ && groupingSize == other.groupingSize
1930+ && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
1931+ && parseBigDecimal == other.parseBigDecimal
1932+ && useExponentialNotation == other.useExponentialNotation
1933+ && (!useExponentialNotation ||
1934+ minExponentDigits == other.minExponentDigits)
1935+ && maximumIntegerDigits == other.maximumIntegerDigits
1936+ && minimumIntegerDigits == other.minimumIntegerDigits
1937+ && maximumFractionDigits == other.maximumFractionDigits
1938+ && minimumFractionDigits == other.minimumFractionDigits
1939+ && roundingMode == other.roundingMode
1940+ && symbols.equals(other.symbols);
1941+ }
1942+
1943+ /**
1944+ * Overrides hashCode
1945+ */
1946+ public int hashCode() {
1947+ return super.hashCode() * 37 + positivePrefix.hashCode();
1948+ // just enough fields for a reasonable distribution
1949+ }
1950+
1951+ /**
1952+ * Synthesizes a pattern string that represents the current state
1953+ * of this Format object.
1954+ * @see #applyPattern
1955+ */
1956+ public String toPattern() {
1957+ return toPattern( false );
1958+ }
1959+
1960+ /**
1961+ * Synthesizes a localized pattern string that represents the current
1962+ * state of this Format object.
1963+ * @see #applyPattern
1964+ */
1965+ public String toLocalizedPattern() {
1966+ return toPattern( true );
1967+ }
1968+
1969+ /**
1970+ * Expand the affix pattern strings into the expanded affix strings. If any
1971+ * affix pattern string is null, do not expand it. This method should be
1972+ * called any time the symbols or the affix patterns change in order to keep
1973+ * the expanded affix strings up to date.
1974+ */
1975+ private void expandAffixes() {
1976+ // Reuse one StringBuffer for better performance
1977+ StringBuffer buffer = new StringBuffer();
1978+ if (posPrefixPattern != null) {
1979+ positivePrefix = expandAffix(posPrefixPattern, buffer);
1980+ positivePrefixFieldPositions = null;
1981+ }
1982+ if (posSuffixPattern != null) {
1983+ positiveSuffix = expandAffix(posSuffixPattern, buffer);
1984+ positiveSuffixFieldPositions = null;
1985+ }
1986+ if (negPrefixPattern != null) {
1987+ negativePrefix = expandAffix(negPrefixPattern, buffer);
1988+ negativePrefixFieldPositions = null;
1989+ }
1990+ if (negSuffixPattern != null) {
1991+ negativeSuffix = expandAffix(negSuffixPattern, buffer);
1992+ negativeSuffixFieldPositions = null;
1993+ }
1994+ }
1995+
1996+ /**
1997+ * Expand an affix pattern into an affix string. All characters in the
1998+ * pattern are literal unless prefixed by QUOTE. The following characters
1999+ * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
2000+ * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
2001+ * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
2002+ * currency code. Any other character after a QUOTE represents itself.
2003+ * QUOTE must be followed by another character; QUOTE may not occur by
2004+ * itself at the end of the pattern.
2005+ *
2006+ * @param pattern the non-null, possibly empty pattern
2007+ * @param buffer a scratch StringBuffer; its contents will be lost
2008+ * @return the expanded equivalent of pattern
2009+ */
2010+ private String expandAffix(String pattern, StringBuffer buffer) {
2011+ buffer.setLength(0);
2012+ for (int i=0; i<pattern.length(); ) {
2013+ char c = pattern.charAt(i++);
2014+ if (c == QUOTE) {
2015+ c = pattern.charAt(i++);
2016+ switch (c) {
2017+ case CURRENCY_SIGN:
2018+ if (i<pattern.length() &&
2019+ pattern.charAt(i) == CURRENCY_SIGN) {
2020+ ++i;
2021+ buffer.append(symbols.getInternationalCurrencySymbol());
2022+ } else {
2023+ buffer.append(symbols.getCurrencySymbol());
2024+ }
2025+ continue;
2026+ case PATTERN_PERCENT:
2027+ c = symbols.getPercent();
2028+ break;
2029+ case PATTERN_PER_MILLE:
2030+ c = symbols.getPerMill();
2031+ break;
2032+ case PATTERN_MINUS:
2033+ c = symbols.getMinusSign();
2034+ break;
2035+ }
2036+ }
2037+ buffer.append(c);
2038+ }
2039+ return buffer.toString();
2040+ }
2041+
2042+ /**
2043+ * Expand an affix pattern into an array of FieldPositions describing
2044+ * how the pattern would be expanded.
2045+ * All characters in the
2046+ * pattern are literal unless prefixed by QUOTE. The following characters
2047+ * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
2048+ * PATTERN_MINUS, and CURRENCY_SIGN. If CURRENCY_SIGN is doubled (QUOTE +
2049+ * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
2050+ * currency code. Any other character after a QUOTE represents itself.
2051+ * QUOTE must be followed by another character; QUOTE may not occur by
2052+ * itself at the end of the pattern.
2053+ *
2054+ * @param pattern the non-null, possibly empty pattern
2055+ * @return FieldPosition array of the resulting fields.
2056+ */
2057+ private FieldPosition[] expandAffix(String pattern) {
2058+ ArrayList positions = null;
2059+ int stringIndex = 0;
2060+ for (int i=0; i<pattern.length(); ) {
2061+ char c = pattern.charAt(i++);
2062+ if (c == QUOTE) {
2063+ int field = -1;
2064+ Format.Field fieldID = null;
2065+ c = pattern.charAt(i++);
2066+ switch (c) {
2067+ case CURRENCY_SIGN:
2068+ String string;
2069+ if (i<pattern.length() &&
2070+ pattern.charAt(i) == CURRENCY_SIGN) {
2071+ ++i;
2072+ string = symbols.getInternationalCurrencySymbol();
2073+ } else {
2074+ string = symbols.getCurrencySymbol();
2075+ }
2076+ if (string.length() > 0) {
2077+ if (positions == null) {
2078+ positions = new ArrayList(2);
2079+ }
2080+ FieldPosition fp = new FieldPosition(Field.CURRENCY);
2081+ fp.setBeginIndex(stringIndex);
2082+ fp.setEndIndex(stringIndex + string.length());
2083+ positions.add(fp);
2084+ stringIndex += string.length();
2085+ }
2086+ continue;
2087+ case PATTERN_PERCENT:
2088+ c = symbols.getPercent();
2089+ field = -1;
2090+ fieldID = Field.PERCENT;
2091+ break;
2092+ case PATTERN_PER_MILLE:
2093+ c = symbols.getPerMill();
2094+ field = -1;
2095+ fieldID = Field.PERMILLE;
2096+ break;
2097+ case PATTERN_MINUS:
2098+ c = symbols.getMinusSign();
2099+ field = -1;
2100+ fieldID = Field.SIGN;
2101+ break;
2102+ }
2103+ if (fieldID != null) {
2104+ if (positions == null) {
2105+ positions = new ArrayList(2);
2106+ }
2107+ FieldPosition fp = new FieldPosition(fieldID, field);
2108+ fp.setBeginIndex(stringIndex);
2109+ fp.setEndIndex(stringIndex + 1);
2110+ positions.add(fp);
2111+ }
2112+ }
2113+ stringIndex++;
2114+ }
2115+ if (positions != null) {
2116+ return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
2117+ }
2118+ return EmptyFieldPositionArray;
2119+ }
2120+
2121+ /**
2122+ * Appends an affix pattern to the given StringBuffer, quoting special
2123+ * characters as needed. Uses the internal affix pattern, if that exists,
2124+ * or the literal affix, if the internal affix pattern is null. The
2125+ * appended string will generate the same affix pattern (or literal affix)
2126+ * when passed to toPattern().
2127+ *
2128+ * @param buffer the affix string is appended to this
2129+ * @param affixPattern a pattern such as posPrefixPattern; may be null
2130+ * @param expAffix a corresponding expanded affix, such as positivePrefix.
2131+ * Ignored unless affixPattern is null. If affixPattern is null, then
2132+ * expAffix is appended as a literal affix.
2133+ * @param localized true if the appended pattern should contain localized
2134+ * pattern characters; otherwise, non-localized pattern chars are appended
2135+ */
2136+ private void appendAffix(StringBuffer buffer, String affixPattern,
2137+ String expAffix, boolean localized) {
2138+ if (affixPattern == null) {
2139+ appendAffix(buffer, expAffix, localized);
2140+ } else {
2141+ int i;
2142+ for (int pos=0; pos<affixPattern.length(); pos=i) {
2143+ i = affixPattern.indexOf(QUOTE, pos);
2144+ if (i < 0) {
2145+ appendAffix(buffer, affixPattern.substring(pos), localized);
2146+ break;
2147+ }
2148+ if (i > pos) {
2149+ appendAffix(buffer, affixPattern.substring(pos, i), localized);
2150+ }
2151+ char c = affixPattern.charAt(++i);
2152+ ++i;
2153+ if (c == QUOTE) {
2154+ buffer.append(c);
2155+ // Fall through and append another QUOTE below
2156+ } else if (c == CURRENCY_SIGN &&
2157+ i<affixPattern.length() &&
2158+ affixPattern.charAt(i) == CURRENCY_SIGN) {
2159+ ++i;
2160+ buffer.append(c);
2161+ // Fall through and append another CURRENCY_SIGN below
2162+ } else if (localized) {
2163+ switch (c) {
2164+ case PATTERN_PERCENT:
2165+ c = symbols.getPercent();
2166+ break;
2167+ case PATTERN_PER_MILLE:
2168+ c = symbols.getPerMill();
2169+ break;
2170+ case PATTERN_MINUS:
2171+ c = symbols.getMinusSign();
2172+ break;
2173+ }
2174+ }
2175+ buffer.append(c);
2176+ }
2177+ }
2178+ }
2179+
2180+ /**
2181+ * Append an affix to the given StringBuffer, using quotes if
2182+ * there are special characters. Single quotes themselves must be
2183+ * escaped in either case.
2184+ */
2185+ private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
2186+ boolean needQuote;
2187+ if (localized) {
2188+ needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
2189+ || affix.indexOf(symbols.getGroupingSeparator()) >= 0
2190+ || affix.indexOf(symbols.getDecimalSeparator()) >= 0
2191+ || affix.indexOf(symbols.getPercent()) >= 0
2192+ || affix.indexOf(symbols.getPerMill()) >= 0
2193+ || affix.indexOf(symbols.getDigit()) >= 0
2194+ || affix.indexOf(symbols.getPatternSeparator()) >= 0
2195+ || affix.indexOf(symbols.getMinusSign()) >= 0
2196+ || affix.indexOf(CURRENCY_SIGN) >= 0;
2197+ }
2198+ else {
2199+ needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
2200+ || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
2201+ || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
2202+ || affix.indexOf(PATTERN_PERCENT) >= 0
2203+ || affix.indexOf(PATTERN_PER_MILLE) >= 0
2204+ || affix.indexOf(PATTERN_DIGIT) >= 0
2205+ || affix.indexOf(PATTERN_SEPARATOR) >= 0
2206+ || affix.indexOf(PATTERN_MINUS) >= 0
2207+ || affix.indexOf(CURRENCY_SIGN) >= 0;
2208+ }
2209+ if (needQuote) buffer.append('\'');
2210+ if (affix.indexOf('\'') < 0) buffer.append(affix);
2211+ else {
2212+ for (int j=0; j<affix.length(); ++j) {
2213+ char c = affix.charAt(j);
2214+ buffer.append(c);
2215+ if (c == '\'') buffer.append(c);
2216+ }
2217+ }
2218+ if (needQuote) buffer.append('\'');
2219+ }
2220+
2221+ /**
2222+ * Does the real work of generating a pattern. */
2223+ private String toPattern(boolean localized) {
2224+ StringBuffer result = new StringBuffer();
2225+ for (int j = 1; j >= 0; --j) {
2226+ if (j == 1)
2227+ appendAffix(result, posPrefixPattern, positivePrefix, localized);
2228+ else appendAffix(result, negPrefixPattern, negativePrefix, localized);
2229+ int i;
2230+ int digitCount = useExponentialNotation
2231+ ? getMaximumIntegerDigits()
2232+ : Math.max(groupingSize, getMinimumIntegerDigits())+1;
2233+ for (i = digitCount; i > 0; --i) {
2234+ if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
2235+ i % groupingSize == 0) {
2236+ result.append(localized ? symbols.getGroupingSeparator() :
2237+ PATTERN_GROUPING_SEPARATOR);
2238+ }
2239+ result.append(i <= getMinimumIntegerDigits()
2240+ ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
2241+ : (localized ? symbols.getDigit() : PATTERN_DIGIT));
2242+ }
2243+ if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
2244+ result.append(localized ? symbols.getDecimalSeparator() :
2245+ PATTERN_DECIMAL_SEPARATOR);
2246+ for (i = 0; i < getMaximumFractionDigits(); ++i) {
2247+ if (i < getMinimumFractionDigits()) {
2248+ result.append(localized ? symbols.getZeroDigit() :
2249+ PATTERN_ZERO_DIGIT);
2250+ } else {
2251+ result.append(localized ? symbols.getDigit() :
2252+ PATTERN_DIGIT);
2253+ }
2254+ }
2255+ if (useExponentialNotation)
2256+ {
2257+ result.append(localized ? symbols.getExponentSeparator() :
2258+ PATTERN_EXPONENT);
2259+ for (i=0; i<minExponentDigits; ++i)
2260+ result.append(localized ? symbols.getZeroDigit() :
2261+ PATTERN_ZERO_DIGIT);
2262+ }
2263+ if (j == 1) {
2264+ appendAffix(result, posSuffixPattern, positiveSuffix, localized);
2265+ if ((negSuffixPattern == posSuffixPattern && // n == p == null
2266+ negativeSuffix.equals(positiveSuffix))
2267+ || (negSuffixPattern != null &&
2268+ negSuffixPattern.equals(posSuffixPattern))) {
2269+ if ((negPrefixPattern != null && posPrefixPattern != null &&
2270+ negPrefixPattern.equals("'-" + posPrefixPattern)) ||
2271+ (negPrefixPattern == posPrefixPattern && // n == p == null
2272+ negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
2273+ break;
2274+ }
2275+ result.append(localized ? symbols.getPatternSeparator() :
2276+ PATTERN_SEPARATOR);
2277+ } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
2278+ }
2279+ return result.toString();
2280+ }
2281+
2282+ /**
2283+ * Apply the given pattern to this Format object. A pattern is a
2284+ * short-hand specification for the various formatting properties.
2285+ * These properties can also be changed individually through the
2286+ * various setter methods.
2287+ * <p>
2288+ * There is no limit to integer digits set
2289+ * by this routine, since that is the typical end-user desire;
2290+ * use setMaximumInteger if you want to set a real value.
2291+ * For negative numbers, use a second pattern, separated by a semicolon
2292+ * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
2293+ * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
2294+ * a maximum of 2 fraction digits.
2295+ * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
2296+ * parentheses.
2297+ * <p>In negative patterns, the minimum and maximum counts are ignored;
2298+ * these are presumed to be set in the positive pattern.
2299+ *
2300+ * @exception NullPointerException if <code>pattern</code> is null
2301+ * @exception IllegalArgumentException if the given pattern is invalid.
2302+ */
2303+ public void applyPattern(String pattern) {
2304+ applyPattern(pattern, false);
2305+ }
2306+
2307+ /**
2308+ * Apply the given pattern to this Format object. The pattern
2309+ * is assumed to be in a localized notation. A pattern is a
2310+ * short-hand specification for the various formatting properties.
2311+ * These properties can also be changed individually through the
2312+ * various setter methods.
2313+ * <p>
2314+ * There is no limit to integer digits set
2315+ * by this routine, since that is the typical end-user desire;
2316+ * use setMaximumInteger if you want to set a real value.
2317+ * For negative numbers, use a second pattern, separated by a semicolon
2318+ * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
2319+ * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
2320+ * a maximum of 2 fraction digits.
2321+ * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
2322+ * parentheses.
2323+ * <p>In negative patterns, the minimum and maximum counts are ignored;
2324+ * these are presumed to be set in the positive pattern.
2325+ *
2326+ * @exception NullPointerException if <code>pattern</code> is null
2327+ * @exception IllegalArgumentException if the given pattern is invalid.
2328+ */
2329+ public void applyLocalizedPattern(String pattern) {
2330+ applyPattern(pattern, true);
2331+ }
2332+
2333+ /**
2334+ * Does the real work of applying a pattern.
2335+ */
2336+ private void applyPattern(String pattern, boolean localized) {
2337+ char zeroDigit = PATTERN_ZERO_DIGIT;
2338+ char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
2339+ char decimalSeparator = PATTERN_DECIMAL_SEPARATOR;
2340+ char percent = PATTERN_PERCENT;
2341+ char perMill = PATTERN_PER_MILLE;
2342+ char digit = PATTERN_DIGIT;
2343+ char separator = PATTERN_SEPARATOR;
2344+ String exponent = PATTERN_EXPONENT;
2345+ char minus = PATTERN_MINUS;
2346+ if (localized) {
2347+ zeroDigit = symbols.getZeroDigit();
2348+ groupingSeparator = symbols.getGroupingSeparator();
2349+ decimalSeparator = symbols.getDecimalSeparator();
2350+ percent = symbols.getPercent();
2351+ perMill = symbols.getPerMill();
2352+ digit = symbols.getDigit();
2353+ separator = symbols.getPatternSeparator();
2354+ exponent = symbols.getExponentSeparator();
2355+ minus = symbols.getMinusSign();
2356+ }
2357+ boolean gotNegative = false;
2358+ decimalSeparatorAlwaysShown = false;
2359+ isCurrencyFormat = false;
2360+ useExponentialNotation = false;
2361+
2362+ // Two variables are used to record the subrange of the pattern
2363+ // occupied by phase 1. This is used during the processing of the
2364+ // second pattern (the one representing negative numbers) to ensure
2365+ // that no deviation exists in phase 1 between the two patterns.
2366+ int phaseOneStart = 0;
2367+ int phaseOneLength = 0;
2368+
2369+ int start = 0;
2370+ for (int j = 1; j >= 0 && start < pattern.length(); --j) {
2371+ boolean inQuote = false;
2372+ StringBuffer prefix = new StringBuffer();
2373+ StringBuffer suffix = new StringBuffer();
2374+ int decimalPos = -1;
2375+ int multiplier = 1;
2376+ int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
2377+ byte groupingCount = -1;
2378+
2379+ // The phase ranges from 0 to 2. Phase 0 is the prefix. Phase 1 is
2380+ // the section of the pattern with digits, decimal separator,
2381+ // grouping characters. Phase 2 is the suffix. In phases 0 and 2,
2382+ // percent, per mille, and currency symbols are recognized and
2383+ // translated. The separation of the characters into phases is
2384+ // strictly enforced; if phase 1 characters are to appear in the
2385+ // suffix, for example, they must be quoted.
2386+ int phase = 0;
2387+
2388+ // The affix is either the prefix or the suffix.
2389+ StringBuffer affix = prefix;
2390+
2391+ for (int pos = start; pos < pattern.length(); ++pos) {
2392+ char ch = pattern.charAt(pos);
2393+ switch (phase) {
2394+ case 0:
2395+ case 2:
2396+ // Process the prefix / suffix characters
2397+ if (inQuote) {
2398+ // A quote within quotes indicates either the closing
2399+ // quote or two quotes, which is a quote literal. That
2400+ // is, we have the second quote in 'do' or 'don''t'.
2401+ if (ch == QUOTE) {
2402+ if ((pos+1) < pattern.length() &&
2403+ pattern.charAt(pos+1) == QUOTE) {
2404+ ++pos;
2405+ affix.append("''"); // 'don''t'
2406+ } else {
2407+ inQuote = false; // 'do'
2408+ }
2409+ continue;
2410+ }
2411+ } else {
2412+ // Process unquoted characters seen in prefix or suffix
2413+ // phase.
2414+ if (ch == digit ||
2415+ ch == zeroDigit ||
2416+ ch == groupingSeparator ||
2417+ ch == decimalSeparator) {
2418+ phase = 1;
2419+ if (j == 1) {
2420+ phaseOneStart = pos;
2421+ }
2422+ --pos; // Reprocess this character
2423+ continue;
2424+ } else if (ch == CURRENCY_SIGN) {
2425+ // Use lookahead to determine if the currency sign
2426+ // is doubled or not.
2427+ boolean doubled = (pos + 1) < pattern.length() &&
2428+ pattern.charAt(pos + 1) == CURRENCY_SIGN;
2429+ if (doubled) { // Skip over the doubled character
2430+ ++pos;
2431+ }
2432+ isCurrencyFormat = true;
2433+ affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
2434+ continue;
2435+ } else if (ch == QUOTE) {
2436+ // A quote outside quotes indicates either the
2437+ // opening quote or two quotes, which is a quote
2438+ // literal. That is, we have the first quote in 'do'
2439+ // or o''clock.
2440+ if (ch == QUOTE) {
2441+ if ((pos+1) < pattern.length() &&
2442+ pattern.charAt(pos+1) == QUOTE) {
2443+ ++pos;
2444+ affix.append("''"); // o''clock
2445+ } else {
2446+ inQuote = true; // 'do'
2447+ }
2448+ continue;
2449+ }
2450+ } else if (ch == separator) {
2451+ // Don't allow separators before we see digit
2452+ // characters of phase 1, and don't allow separators
2453+ // in the second pattern (j == 0).
2454+ if (phase == 0 || j == 0) {
2455+ throw new IllegalArgumentException("Unquoted special character '" +
2456+ ch + "' in pattern \"" + pattern + '"');
2457+ }
2458+ start = pos + 1;
2459+ pos = pattern.length();
2460+ continue;
2461+ }
2462+
2463+ // Next handle characters which are appended directly.
2464+ else if (ch == percent) {
2465+ if (multiplier != 1) {
2466+ throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
2467+ pattern + '"');
2468+ }
2469+ multiplier = 100;
2470+ affix.append("'%");
2471+ continue;
2472+ } else if (ch == perMill) {
2473+ if (multiplier != 1) {
2474+ throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
2475+ pattern + '"');
2476+ }
2477+ multiplier = 1000;
2478+ affix.append("'\u2030");
2479+ continue;
2480+ } else if (ch == minus) {
2481+ affix.append("'-");
2482+ continue;
2483+ }
2484+ }
2485+ // Note that if we are within quotes, or if this is an
2486+ // unquoted, non-special character, then we usually fall
2487+ // through to here.
2488+ affix.append(ch);
2489+ break;
2490+
2491+ case 1:
2492+ // Phase one must be identical in the two sub-patterns. We
2493+ // enforce this by doing a direct comparison. While
2494+ // processing the first sub-pattern, we just record its
2495+ // length. While processing the second, we compare
2496+ // characters.
2497+ if (j == 1) {
2498+ ++phaseOneLength;
2499+ } else {
2500+ if (--phaseOneLength == 0) {
2501+ phase = 2;
2502+ affix = suffix;
2503+ }
2504+ continue;
2505+ }
2506+
2507+ // Process the digits, decimal, and grouping characters. We
2508+ // record five pieces of information. We expect the digits
2509+ // to occur in the pattern ####0000.####, and we record the
2510+ // number of left digits, zero (central) digits, and right
2511+ // digits. The position of the last grouping character is
2512+ // recorded (should be somewhere within the first two blocks
2513+ // of characters), as is the position of the decimal point,
2514+ // if any (should be in the zero digits). If there is no
2515+ // decimal point, then there should be no right digits.
2516+ if (ch == digit) {
2517+ if (zeroDigitCount > 0) {
2518+ ++digitRightCount;
2519+ } else {
2520+ ++digitLeftCount;
2521+ }
2522+ if (groupingCount >= 0 && decimalPos < 0) {
2523+ ++groupingCount;
2524+ }
2525+ } else if (ch == zeroDigit) {
2526+ if (digitRightCount > 0) {
2527+ throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
2528+ pattern + '"');
2529+ }
2530+ ++zeroDigitCount;
2531+ if (groupingCount >= 0 && decimalPos < 0) {
2532+ ++groupingCount;
2533+ }
2534+ } else if (ch == groupingSeparator) {
2535+ groupingCount = 0;
2536+ } else if (ch == decimalSeparator) {
2537+ if (decimalPos >= 0) {
2538+ throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
2539+ pattern + '"');
2540+ }
2541+ decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
2542+ } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
2543+ if (useExponentialNotation) {
2544+ throw new IllegalArgumentException("Multiple exponential " +
2545+ "symbols in pattern \"" + pattern + '"');
2546+ }
2547+ useExponentialNotation = true;
2548+ minExponentDigits = 0;
2549+
2550+ // Use lookahead to parse out the exponential part
2551+ // of the pattern, then jump into phase 2.
2552+ pos = pos+exponent.length();
2553+ while (pos < pattern.length() &&
2554+ pattern.charAt(pos) == zeroDigit) {
2555+ ++minExponentDigits;
2556+ ++phaseOneLength;
2557+ ++pos;
2558+ }
2559+
2560+ if ((digitLeftCount + zeroDigitCount) < 1 ||
2561+ minExponentDigits < 1) {
2562+ throw new IllegalArgumentException("Malformed exponential " +
2563+ "pattern \"" + pattern + '"');
2564+ }
2565+
2566+ // Transition to phase 2
2567+ phase = 2;
2568+ affix = suffix;
2569+ --pos;
2570+ continue;
2571+ } else {
2572+ phase = 2;
2573+ affix = suffix;
2574+ --pos;
2575+ --phaseOneLength;
2576+ continue;
2577+ }
2578+ break;
2579+ }
2580+ }
2581+
2582+ // Handle patterns with no '0' pattern character. These patterns
2583+ // are legal, but must be interpreted. "##.###" -> "#0.###".
2584+ // ".###" -> ".0##".
2585+ /* We allow patterns of the form "####" to produce a zeroDigitCount
2586+ * of zero (got that?); although this seems like it might make it
2587+ * possible for format() to produce empty strings, format() checks
2588+ * for this condition and outputs a zero digit in this situation.
2589+ * Having a zeroDigitCount of zero yields a minimum integer digits
2590+ * of zero, which allows proper round-trip patterns. That is, we
2591+ * don't want "#" to become "#0" when toPattern() is called (even
2592+ * though that's what it really is, semantically).
2593+ */
2594+ if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
2595+ // Handle "###.###" and "###." and ".###"
2596+ int n = decimalPos;
2597+ if (n == 0) { // Handle ".###"
2598+ ++n;
2599+ }
2600+ digitRightCount = digitLeftCount - n;
2601+ digitLeftCount = n - 1;
2602+ zeroDigitCount = 1;
2603+ }
2604+
2605+ // Do syntax checking on the digits.
2606+ if ((decimalPos < 0 && digitRightCount > 0) ||
2607+ (decimalPos >= 0 && (decimalPos < digitLeftCount ||
2608+ decimalPos > (digitLeftCount + zeroDigitCount))) ||
2609+ groupingCount == 0 || inQuote) {
2610+ throw new IllegalArgumentException("Malformed pattern \"" +
2611+ pattern + '"');
2612+ }
2613+
2614+ if (j == 1) {
2615+ posPrefixPattern = prefix.toString();
2616+ posSuffixPattern = suffix.toString();
2617+ negPrefixPattern = posPrefixPattern; // assume these for now
2618+ negSuffixPattern = posSuffixPattern;
2619+ int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
2620+ /* The effectiveDecimalPos is the position the decimal is at or
2621+ * would be at if there is no decimal. Note that if decimalPos<0,
2622+ * then digitTotalCount == digitLeftCount + zeroDigitCount.
2623+ */
2624+ int effectiveDecimalPos = decimalPos >= 0 ?
2625+ decimalPos : digitTotalCount;
2626+ setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
2627+ setMaximumIntegerDigits(useExponentialNotation ?
2628+ digitLeftCount + getMinimumIntegerDigits() :
2629+ MAXIMUM_INTEGER_DIGITS);
2630+ setMaximumFractionDigits(decimalPos >= 0 ?
2631+ (digitTotalCount - decimalPos) : 0);
2632+ setMinimumFractionDigits(decimalPos >= 0 ?
2633+ (digitLeftCount + zeroDigitCount - decimalPos) : 0);
2634+ setGroupingUsed(groupingCount > 0);
2635+ this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
2636+ this.multiplier = multiplier;
2637+ setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
2638+ decimalPos == digitTotalCount);
2639+ } else {
2640+ negPrefixPattern = prefix.toString();
2641+ negSuffixPattern = suffix.toString();
2642+ gotNegative = true;
2643+ }
2644+ }
2645+
2646+ if (pattern.length() == 0) {
2647+ posPrefixPattern = posSuffixPattern = "";
2648+ setMinimumIntegerDigits(0);
2649+ setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
2650+ setMinimumFractionDigits(0);
2651+ setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
2652+ }
2653+
2654+ // If there was no negative pattern, or if the negative pattern is
2655+ // identical to the positive pattern, then prepend the minus sign to
2656+ // the positive pattern to form the negative pattern.
2657+ if (!gotNegative ||
2658+ (negPrefixPattern.equals(posPrefixPattern)
2659+ && negSuffixPattern.equals(posSuffixPattern))) {
2660+ negSuffixPattern = posSuffixPattern;
2661+ negPrefixPattern = "'-" + posPrefixPattern;
2662+ }
2663+
2664+ expandAffixes();
2665+ }
2666+
2667+ /**
2668+ * Sets the maximum number of digits allowed in the integer portion of a
2669+ * number.
2670+ * For formatting numbers other than <code>BigInteger</code> and
2671+ * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
2672+ * 309 is used. Negative input values are replaced with 0.
2673+ * @see NumberFormat#setMaximumIntegerDigits
2674+ */
2675+ public void setMaximumIntegerDigits(int newValue) {
2676+ maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
2677+ super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
2678+ DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
2679+ if (minimumIntegerDigits > maximumIntegerDigits) {
2680+ minimumIntegerDigits = maximumIntegerDigits;
2681+ super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
2682+ DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
2683+ }
2684+ }
2685+
2686+ /**
2687+ * Sets the minimum number of digits allowed in the integer portion of a
2688+ * number.
2689+ * For formatting numbers other than <code>BigInteger</code> and
2690+ * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
2691+ * 309 is used. Negative input values are replaced with 0.
2692+ * @see NumberFormat#setMinimumIntegerDigits
2693+ */
2694+ public void setMinimumIntegerDigits(int newValue) {
2695+ minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
2696+ super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
2697+ DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
2698+ if (minimumIntegerDigits > maximumIntegerDigits) {
2699+ maximumIntegerDigits = minimumIntegerDigits;
2700+ super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
2701+ DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
2702+ }
2703+ }
2704+
2705+ /**
2706+ * Sets the maximum number of digits allowed in the fraction portion of a
2707+ * number.
2708+ * For formatting numbers other than <code>BigInteger</code> and
2709+ * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
2710+ * 340 is used. Negative input values are replaced with 0.
2711+ * @see NumberFormat#setMaximumFractionDigits
2712+ */
2713+ public void setMaximumFractionDigits(int newValue) {
2714+ maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
2715+ super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
2716+ DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
2717+ if (minimumFractionDigits > maximumFractionDigits) {
2718+ minimumFractionDigits = maximumFractionDigits;
2719+ super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
2720+ DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
2721+ }
2722+ }
2723+
2724+ /**
2725+ * Sets the minimum number of digits allowed in the fraction portion of a
2726+ * number.
2727+ * For formatting numbers other than <code>BigInteger</code> and
2728+ * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
2729+ * 340 is used. Negative input values are replaced with 0.
2730+ * @see NumberFormat#setMinimumFractionDigits
2731+ */
2732+ public void setMinimumFractionDigits(int newValue) {
2733+ minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
2734+ super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
2735+ DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
2736+ if (minimumFractionDigits > maximumFractionDigits) {
2737+ maximumFractionDigits = minimumFractionDigits;
2738+ super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
2739+ DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
2740+ }
2741+ }
2742+
2743+ /**
2744+ * Gets the maximum number of digits allowed in the integer portion of a
2745+ * number.
2746+ * For formatting numbers other than <code>BigInteger</code> and
2747+ * <code>BigDecimal</code> objects, the lower of the return value and
2748+ * 309 is used.
2749+ * @see #setMaximumIntegerDigits
2750+ */
2751+ public int getMaximumIntegerDigits() {
2752+ return maximumIntegerDigits;
2753+ }
2754+
2755+ /**
2756+ * Gets the minimum number of digits allowed in the integer portion of a
2757+ * number.
2758+ * For formatting numbers other than <code>BigInteger</code> and
2759+ * <code>BigDecimal</code> objects, the lower of the return value and
2760+ * 309 is used.
2761+ * @see #setMinimumIntegerDigits
2762+ */
2763+ public int getMinimumIntegerDigits() {
2764+ return minimumIntegerDigits;
2765+ }
2766+
2767+ /**
2768+ * Gets the maximum number of digits allowed in the fraction portion of a
2769+ * number.
2770+ * For formatting numbers other than <code>BigInteger</code> and
2771+ * <code>BigDecimal</code> objects, the lower of the return value and
2772+ * 340 is used.
2773+ * @see #setMaximumFractionDigits
2774+ */
2775+ public int getMaximumFractionDigits() {
2776+ return maximumFractionDigits;
2777+ }
2778+
2779+ /**
2780+ * Gets the minimum number of digits allowed in the fraction portion of a
2781+ * number.
2782+ * For formatting numbers other than <code>BigInteger</code> and
2783+ * <code>BigDecimal</code> objects, the lower of the return value and
2784+ * 340 is used.
2785+ * @see #setMinimumFractionDigits
2786+ */
2787+ public int getMinimumFractionDigits() {
2788+ return minimumFractionDigits;
2789+ }
2790+
2791+ /**
2792+ * Gets the currency used by this decimal format when formatting
2793+ * currency values.
2794+ * The currency is obtained by calling
2795+ * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
2796+ * on this number format's symbols.
2797+ *
2798+ * @return the currency used by this decimal format, or <code>null</code>
2799+ * @since 1.4
2800+ */
2801+ public Currency getCurrency() {
2802+ return symbols.getCurrency();
2803+ }
2804+
2805+ /**
2806+ * Sets the currency used by this number format when formatting
2807+ * currency values. This does not update the minimum or maximum
2808+ * number of fraction digits used by the number format.
2809+ * The currency is set by calling
2810+ * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
2811+ * on this number format's symbols.
2812+ *
2813+ * @param currency the new currency to be used by this decimal format
2814+ * @exception NullPointerException if <code>currency</code> is null
2815+ * @since 1.4
2816+ */
2817+ public void setCurrency(Currency currency) {
2818+ if (currency != symbols.getCurrency()) {
2819+ symbols.setCurrency(currency);
2820+ if (isCurrencyFormat) {
2821+ expandAffixes();
2822+ }
2823+ }
2824+ }
2825+
2826+ /**
2827+ * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
2828+ *
2829+ * @return The <code>RoundingMode</code> used for this DecimalFormat.
2830+ * @see #setRoundingMode(RoundingMode)
2831+ * @since 1.6
2832+ */
2833+ public RoundingMode getRoundingMode() {
2834+ return roundingMode;
2835+ }
2836+
2837+ /**
2838+ * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
2839+ *
2840+ * @param roundingMode The <code>RoundingMode</code> to be used
2841+ * @see #getRoundingMode()
2842+ * @exception NullPointerException if <code>roundingMode</code> is null.
2843+ * @since 1.6
2844+ */
2845+ public void setRoundingMode(RoundingMode roundingMode) {
2846+ if (roundingMode == null) {
2847+ throw new NullPointerException();
2848+ }
2849+
2850+ this.roundingMode = roundingMode;
2851+ digitList.setRoundingMode(roundingMode);
2852+ }
2853+
2854+ /**
2855+ * Adjusts the minimum and maximum fraction digits to values that
2856+ * are reasonable for the currency's default fraction digits.
2857+ */
2858+ void adjustForCurrencyDefaultFractionDigits() {
2859+ Currency currency = symbols.getCurrency();
2860+ if (currency == null) {
2861+ try {
2862+ currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
2863+ } catch (IllegalArgumentException e) {
2864+ }
2865+ }
2866+ if (currency != null) {
2867+ int digits = currency.getDefaultFractionDigits();
2868+ if (digits != -1) {
2869+ int oldMinDigits = getMinimumFractionDigits();
2870+ // Common patterns are "#.##", "#.00", "#".
2871+ // Try to adjust all of them in a reasonable way.
2872+ if (oldMinDigits == getMaximumFractionDigits()) {
2873+ setMinimumFractionDigits(digits);
2874+ setMaximumFractionDigits(digits);
2875+ } else {
2876+ setMinimumFractionDigits(Math.min(digits, oldMinDigits));
2877+ setMaximumFractionDigits(digits);
2878+ }
2879+ }
2880+ }
2881+ }
2882+
2883+ /**
2884+ * Reads the default serializable fields from the stream and performs
2885+ * validations and adjustments for older serialized versions. The
2886+ * validations and adjustments are:
2887+ * <ol>
2888+ * <li>
2889+ * Verify that the superclass's digit count fields correctly reflect
2890+ * the limits imposed on formatting numbers other than
2891+ * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
2892+ * limits are stored in the superclass for serialization compatibility
2893+ * with older versions, while the limits for <code>BigInteger</code> and
2894+ * <code>BigDecimal</code> objects are kept in this class.
2895+ * If, in the superclass, the minimum or maximum integer digit count is
2896+ * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
2897+ * maximum fraction digit count is larger than
2898+ * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
2899+ * and this method throws an <code>InvalidObjectException</code>.
2900+ * <li>
2901+ * If <code>serialVersionOnStream</code> is less than 4, initialize
2902+ * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
2903+ * RoundingMode.HALF_EVEN}. This field is new with version 4.
2904+ * <li>
2905+ * If <code>serialVersionOnStream</code> is less than 3, then call
2906+ * the setters for the minimum and maximum integer and fraction digits with
2907+ * the values of the corresponding superclass getters to initialize the
2908+ * fields in this class. The fields in this class are new with version 3.
2909+ * <li>
2910+ * If <code>serialVersionOnStream</code> is less than 1, indicating that
2911+ * the stream was written by JDK 1.1, initialize
2912+ * <code>useExponentialNotation</code>
2913+ * to false, since it was not present in JDK 1.1.
2914+ * <li>
2915+ * Set <code>serialVersionOnStream</code> to the maximum allowed value so
2916+ * that default serialization will work properly if this object is streamed
2917+ * out again.
2918+ * </ol>
2919+ *
2920+ * <p>Stream versions older than 2 will not have the affix pattern variables
2921+ * <code>posPrefixPattern</code> etc. As a result, they will be initialized
2922+ * to <code>null</code>, which means the affix strings will be taken as
2923+ * literal values. This is exactly what we want, since that corresponds to
2924+ * the pre-version-2 behavior.
2925+ */
2926+ private void readObject(ObjectInputStream stream)
2927+ throws IOException, ClassNotFoundException
2928+ {
2929+ stream.defaultReadObject();
2930+ digitList = new DigitList();
2931+
2932+ if (serialVersionOnStream < 4) {
2933+ setRoundingMode(RoundingMode.HALF_EVEN);
2934+ }
2935+ // We only need to check the maximum counts because NumberFormat
2936+ // .readObject has already ensured that the maximum is greater than the
2937+ // minimum count.
2938+ if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
2939+ super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
2940+ throw new InvalidObjectException("Digit count out of range");
2941+ }
2942+ if (serialVersionOnStream < 3) {
2943+ setMaximumIntegerDigits(super.getMaximumIntegerDigits());
2944+ setMinimumIntegerDigits(super.getMinimumIntegerDigits());
2945+ setMaximumFractionDigits(super.getMaximumFractionDigits());
2946+ setMinimumFractionDigits(super.getMinimumFractionDigits());
2947+ }
2948+ if (serialVersionOnStream < 1) {
2949+ // Didn't have exponential fields
2950+ useExponentialNotation = false;
2951+ }
2952+ serialVersionOnStream = currentSerialVersion;
2953+ }
2954+
2955+ //----------------------------------------------------------------------
2956+ // INSTANCE VARIABLES
2957+ //----------------------------------------------------------------------
2958+
2959+ private transient DigitList digitList = new DigitList();
2960+
2961+ /**
2962+ * The symbol used as a prefix when formatting positive numbers, e.g. "+".
2963+ *
2964+ * @serial
2965+ * @see #getPositivePrefix
2966+ */
2967+ private String positivePrefix = "";
2968+
2969+ /**
2970+ * The symbol used as a suffix when formatting positive numbers.
2971+ * This is often an empty string.
2972+ *
2973+ * @serial
2974+ * @see #getPositiveSuffix
2975+ */
2976+ private String positiveSuffix = "";
2977+
2978+ /**
2979+ * The symbol used as a prefix when formatting negative numbers, e.g. "-".
2980+ *
2981+ * @serial
2982+ * @see #getNegativePrefix
2983+ */
2984+ private String negativePrefix = "-";
2985+
2986+ /**
2987+ * The symbol used as a suffix when formatting negative numbers.
2988+ * This is often an empty string.
2989+ *
2990+ * @serial
2991+ * @see #getNegativeSuffix
2992+ */
2993+ private String negativeSuffix = "";
2994+
2995+ /**
2996+ * The prefix pattern for non-negative numbers. This variable corresponds
2997+ * to <code>positivePrefix</code>.
2998+ *
2999+ * <p>This pattern is expanded by the method <code>expandAffix()</code> to
3000+ * <code>positivePrefix</code> to update the latter to reflect changes in
3001+ * <code>symbols</code>. If this variable is <code>null</code> then
3002+ * <code>positivePrefix</code> is taken as a literal value that does not
3003+ * change when <code>symbols</code> changes. This variable is always
3004+ * <code>null</code> for <code>DecimalFormat</code> objects older than
3005+ * stream version 2 restored from stream.
3006+ *
3007+ * @serial
3008+ * @since 1.3
3009+ */
3010+ private String posPrefixPattern;
3011+
3012+ /**
3013+ * The suffix pattern for non-negative numbers. This variable corresponds
3014+ * to <code>positiveSuffix</code>. This variable is analogous to
3015+ * <code>posPrefixPattern</code>; see that variable for further
3016+ * documentation.
3017+ *
3018+ * @serial
3019+ * @since 1.3
3020+ */
3021+ private String posSuffixPattern;
3022+
3023+ /**
3024+ * The prefix pattern for negative numbers. This variable corresponds
3025+ * to <code>negativePrefix</code>. This variable is analogous to
3026+ * <code>posPrefixPattern</code>; see that variable for further
3027+ * documentation.
3028+ *
3029+ * @serial
3030+ * @since 1.3
3031+ */
3032+ private String negPrefixPattern;
3033+
3034+ /**
3035+ * The suffix pattern for negative numbers. This variable corresponds
3036+ * to <code>negativeSuffix</code>. This variable is analogous to
3037+ * <code>posPrefixPattern</code>; see that variable for further
3038+ * documentation.
3039+ *
3040+ * @serial
3041+ * @since 1.3
3042+ */
3043+ private String negSuffixPattern;
3044+
3045+ /**
3046+ * The multiplier for use in percent, per mille, etc.
3047+ *
3048+ * @serial
3049+ * @see #getMultiplier
3050+ */
3051+ private int multiplier = 1;
3052+
3053+ /**
3054+ * The number of digits between grouping separators in the integer
3055+ * portion of a number. Must be greater than 0 if
3056+ * <code>NumberFormat.groupingUsed</code> is true.
3057+ *
3058+ * @serial
3059+ * @see #getGroupingSize
3060+ * @see java.text.NumberFormat#isGroupingUsed
3061+ */
3062+ private byte groupingSize = 3; // invariant, > 0 if useThousands
3063+
3064+ /**
3065+ * If true, forces the decimal separator to always appear in a formatted
3066+ * number, even if the fractional part of the number is zero.
3067+ *
3068+ * @serial
3069+ * @see #isDecimalSeparatorAlwaysShown
3070+ */
3071+ private boolean decimalSeparatorAlwaysShown = false;
3072+
3073+ /**
3074+ * If true, parse returns BigDecimal wherever possible.
3075+ *
3076+ * @serial
3077+ * @see #isParseBigDecimal
3078+ * @since 1.5
3079+ */
3080+ private boolean parseBigDecimal = false;
3081+
3082+
3083+ /**
3084+ * True if this object represents a currency format. This determines
3085+ * whether the monetary decimal separator is used instead of the normal one.
3086+ */
3087+ private transient boolean isCurrencyFormat = false;
3088+
3089+ /**
3090+ * The <code>DecimalFormatSymbols</code> object used by this format.
3091+ * It contains the symbols used to format numbers, e.g. the grouping separator,
3092+ * decimal separator, and so on.
3093+ *
3094+ * @serial
3095+ * @see #setDecimalFormatSymbols
3096+ * @see java.text.DecimalFormatSymbols
3097+ */
3098+ private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
3099+
3100+ /**
3101+ * True to force the use of exponential (i.e. scientific) notation when formatting
3102+ * numbers.
3103+ *
3104+ * @serial
3105+ * @since 1.2
3106+ */
3107+ private boolean useExponentialNotation; // Newly persistent in the Java 2 platform v.1.2
3108+
3109+ /**
3110+ * FieldPositions describing the positive prefix String. This is
3111+ * lazily created. Use <code>getPositivePrefixFieldPositions</code>
3112+ * when needed.
3113+ */
3114+ private transient FieldPosition[] positivePrefixFieldPositions;
3115+
3116+ /**
3117+ * FieldPositions describing the positive suffix String. This is
3118+ * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
3119+ * when needed.
3120+ */
3121+ private transient FieldPosition[] positiveSuffixFieldPositions;
3122+
3123+ /**
3124+ * FieldPositions describing the negative prefix String. This is
3125+ * lazily created. Use <code>getNegativePrefixFieldPositions</code>
3126+ * when needed.
3127+ */
3128+ private transient FieldPosition[] negativePrefixFieldPositions;
3129+
3130+ /**
3131+ * FieldPositions describing the negative suffix String. This is
3132+ * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
3133+ * when needed.
3134+ */
3135+ private transient FieldPosition[] negativeSuffixFieldPositions;
3136+
3137+ /**
3138+ * The minimum number of digits used to display the exponent when a number is
3139+ * formatted in exponential notation. This field is ignored if
3140+ * <code>useExponentialNotation</code> is not true.
3141+ *
3142+ * @serial
3143+ * @since 1.2
3144+ */
3145+ private byte minExponentDigits; // Newly persistent in the Java 2 platform v.1.2
3146+
3147+ /**
3148+ * The maximum number of digits allowed in the integer portion of a
3149+ * <code>BigInteger</code> or <code>BigDecimal</code> number.
3150+ * <code>maximumIntegerDigits</code> must be greater than or equal to
3151+ * <code>minimumIntegerDigits</code>.
3152+ *
3153+ * @serial
3154+ * @see #getMaximumIntegerDigits
3155+ * @since 1.5
3156+ */
3157+ private int maximumIntegerDigits = super.getMaximumIntegerDigits();
3158+
3159+ /**
3160+ * The minimum number of digits allowed in the integer portion of a
3161+ * <code>BigInteger</code> or <code>BigDecimal</code> number.
3162+ * <code>minimumIntegerDigits</code> must be less than or equal to
3163+ * <code>maximumIntegerDigits</code>.
3164+ *
3165+ * @serial
3166+ * @see #getMinimumIntegerDigits
3167+ * @since 1.5
3168+ */
3169+ private int minimumIntegerDigits = super.getMinimumIntegerDigits();
3170+
3171+ /**
3172+ * The maximum number of digits allowed in the fractional portion of a
3173+ * <code>BigInteger</code> or <code>BigDecimal</code> number.
3174+ * <code>maximumFractionDigits</code> must be greater than or equal to
3175+ * <code>minimumFractionDigits</code>.
3176+ *
3177+ * @serial
3178+ * @see #getMaximumFractionDigits
3179+ * @since 1.5
3180+ */
3181+ private int maximumFractionDigits = super.getMaximumFractionDigits();
3182+
3183+ /**
3184+ * The minimum number of digits allowed in the fractional portion of a
3185+ * <code>BigInteger</code> or <code>BigDecimal</code> number.
3186+ * <code>minimumFractionDigits</code> must be less than or equal to
3187+ * <code>maximumFractionDigits</code>.
3188+ *
3189+ * @serial
3190+ * @see #getMinimumFractionDigits
3191+ * @since 1.5
3192+ */
3193+ private int minimumFractionDigits = super.getMinimumFractionDigits();
3194+
3195+ /**
3196+ * The {@link java.math.RoundingMode} used in this DecimalFormat.
3197+ *
3198+ * @serial
3199+ * @since 1.6
3200+ */
3201+ private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
3202+
3203+ //----------------------------------------------------------------------
3204+
3205+ static final int currentSerialVersion = 4;
3206+
3207+ /**
3208+ * The internal serial version which says which version was written.
3209+ * Possible values are:
3210+ * <ul>
3211+ * <li><b>0</b> (default): versions before the Java 2 platform v1.2
3212+ * <li><b>1</b>: version for 1.2, which includes the two new fields
3213+ * <code>useExponentialNotation</code> and
3214+ * <code>minExponentDigits</code>.
3215+ * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
3216+ * <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
3217+ * <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
3218+ * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
3219+ * <code>maximumIntegerDigits</code>,
3220+ * <code>minimumIntegerDigits</code>,
3221+ * <code>maximumFractionDigits</code>,
3222+ * <code>minimumFractionDigits</code>, and
3223+ * <code>parseBigDecimal</code>.
3224+ * <li><b>4</b>: version for 1.6 and later, which adds one new field:
3225+ * <code>roundingMode</code>.
3226+ * </ul>
3227+ * @since 1.2
3228+ * @serial
3229+ */
3230+ private int serialVersionOnStream = currentSerialVersion;
3231+
3232+ //----------------------------------------------------------------------
3233+ // CONSTANTS
3234+ //----------------------------------------------------------------------
3235+
3236+ // Constants for characters used in programmatic (unlocalized) patterns.
3237+ private static final char PATTERN_ZERO_DIGIT = '0';
3238+ private static final char PATTERN_GROUPING_SEPARATOR = ',';
3239+ private static final char PATTERN_DECIMAL_SEPARATOR = '.';
3240+ private static final char PATTERN_PER_MILLE = '\u2030';
3241+ private static final char PATTERN_PERCENT = '%';
3242+ private static final char PATTERN_DIGIT = '#';
3243+ private static final char PATTERN_SEPARATOR = ';';
3244+ private static final String PATTERN_EXPONENT = "E";
3245+ private static final char PATTERN_MINUS = '-';
3246+
3247+ /**
3248+ * The CURRENCY_SIGN is the standard Unicode symbol for currency. It
3249+ * is used in patterns and substituted with either the currency symbol,
3250+ * or if it is doubled, with the international currency symbol. If the
3251+ * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
3252+ * replaced with the monetary decimal separator.
3253+ *
3254+ * The CURRENCY_SIGN is not localized.
3255+ */
3256+ private static final char CURRENCY_SIGN = '\u00A4';
3257+
3258+ private static final char QUOTE = '\'';
3259+
3260+ private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
3261+
3262+ // Upper limit on integer and fraction digits for a Java double
3263+ static final int DOUBLE_INTEGER_DIGITS = 309;
3264+ static final int DOUBLE_FRACTION_DIGITS = 340;
3265+
3266+ // Upper limit on integer and fraction digits for BigDecimal and BigInteger
3267+ static final int MAXIMUM_INTEGER_DIGITS = Integer.MAX_VALUE;
3268+ static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
3269+
3270+ // Proclaim JDK 1.1 serial compatibility.
3271+ static final long serialVersionUID = 864413376551465018L;
3272+
3273+ /**
3274+ * Cache to hold the NumberPattern of a Locale.
3275+ */
3276+ private static final ConcurrentMap<Locale, String> cachedLocaleData
3277+ = new ConcurrentHashMap<Locale, String>(3);
3278+}
java/pkg/java/text/DecimalFormatSymbols$DecimalFormatSymbolsGetter.class+0−0

Binary file not shown.

java/pkg/java/text/DecimalFormatSymbols.class+0−0

Binary file not shown.

java/pkg/java/text/DecimalFormatSymbols.java+837−0
@@ -0,0 +1,837 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.IOException;
42+import java.io.ObjectInputStream;
43+import java.io.Serializable;
44+import java.text.spi.DecimalFormatSymbolsProvider;
45+import java.util.Currency;
46+import java.util.Locale;
47+import java.util.ResourceBundle;
48+import java.util.concurrent.ConcurrentHashMap;
49+
50+import sun.util.LocaleServiceProviderPool;
51+import sun.util.resources.LocaleData;
52+
53+/**
54+ * This class represents the set of symbols (such as the decimal separator,
55+ * the grouping separator, and so on) needed by <code>DecimalFormat</code>
56+ * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
57+ * <code>DecimalFormatSymbols</code> from its locale data. If you need to change any
58+ * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
59+ * your <code>DecimalFormat</code> and modify it.
60+ *
61+ * @see java.util.Locale
62+ * @see DecimalFormat
63+ * @author Mark Davis
64+ * @author Alan Liu
65+ */
66+
67+public class DecimalFormatSymbols implements Cloneable, Serializable {
68+
69+ /**
70+ * Create a DecimalFormatSymbols object for the default locale.
71+ * This constructor can only construct instances for the locales
72+ * supported by the Java runtime environment, not for those
73+ * supported by installed
74+ * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
75+ * implementations. For full locale coverage, use the
76+ * {@link #getInstance(Locale) getInstance} method.
77+ */
78+ public DecimalFormatSymbols() {
79+ initialize( Locale.getDefault(Locale.Category.FORMAT) );
80+ }
81+
82+ /**
83+ * Create a DecimalFormatSymbols object for the given locale.
84+ * This constructor can only construct instances for the locales
85+ * supported by the Java runtime environment, not for those
86+ * supported by installed
87+ * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
88+ * implementations. For full locale coverage, use the
89+ * {@link #getInstance(Locale) getInstance} method.
90+ *
91+ * @exception NullPointerException if <code>locale</code> is null
92+ */
93+ public DecimalFormatSymbols( Locale locale ) {
94+ initialize( locale );
95+ }
96+
97+ /**
98+ * Returns an array of all locales for which the
99+ * <code>getInstance</code> methods of this class can return
100+ * localized instances.
101+ * The returned array represents the union of locales supported by the Java
102+ * runtime and by installed
103+ * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
104+ * implementations. It must contain at least a <code>Locale</code>
105+ * instance equal to {@link java.util.Locale#US Locale.US}.
106+ *
107+ * @return An array of locales for which localized
108+ * <code>DecimalFormatSymbols</code> instances are available.
109+ * @since 1.6
110+ */
111+ public static Locale[] getAvailableLocales() {
112+ LocaleServiceProviderPool pool =
113+ LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
114+ return pool.getAvailableLocales();
115+ }
116+
117+ /**
118+ * Gets the <code>DecimalFormatSymbols</code> instance for the default
119+ * locale. This method provides access to <code>DecimalFormatSymbols</code>
120+ * instances for locales supported by the Java runtime itself as well
121+ * as for those supported by installed
122+ * {@link java.text.spi.DecimalFormatSymbolsProvider
123+ * DecimalFormatSymbolsProvider} implementations.
124+ * @return a <code>DecimalFormatSymbols</code> instance.
125+ * @since 1.6
126+ */
127+ public static final DecimalFormatSymbols getInstance() {
128+ return getInstance(Locale.getDefault(Locale.Category.FORMAT));
129+ }
130+
131+ /**
132+ * Gets the <code>DecimalFormatSymbols</code> instance for the specified
133+ * locale. This method provides access to <code>DecimalFormatSymbols</code>
134+ * instances for locales supported by the Java runtime itself as well
135+ * as for those supported by installed
136+ * {@link java.text.spi.DecimalFormatSymbolsProvider
137+ * DecimalFormatSymbolsProvider} implementations.
138+ * @param locale the desired locale.
139+ * @return a <code>DecimalFormatSymbols</code> instance.
140+ * @exception NullPointerException if <code>locale</code> is null
141+ * @since 1.6
142+ */
143+ public static final DecimalFormatSymbols getInstance(Locale locale) {
144+
145+ // Check whether a provider can provide an implementation that's closer
146+ // to the requested locale than what the Java runtime itself can provide.
147+ LocaleServiceProviderPool pool =
148+ LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
149+ if (pool.hasProviders()) {
150+ DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
151+ DecimalFormatSymbolsGetter.INSTANCE, locale);
152+ if (providersInstance != null) {
153+ return providersInstance;
154+ }
155+ }
156+
157+ return new DecimalFormatSymbols(locale);
158+ }
159+
160+ /**
161+ * Gets the character used for zero. Different for Arabic, etc.
162+ */
163+ public char getZeroDigit() {
164+ return zeroDigit;
165+ }
166+
167+ /**
168+ * Sets the character used for zero. Different for Arabic, etc.
169+ */
170+ public void setZeroDigit(char zeroDigit) {
171+ this.zeroDigit = zeroDigit;
172+ }
173+
174+ /**
175+ * Gets the character used for thousands separator. Different for French, etc.
176+ */
177+ public char getGroupingSeparator() {
178+ return groupingSeparator;
179+ }
180+
181+ /**
182+ * Sets the character used for thousands separator. Different for French, etc.
183+ */
184+ public void setGroupingSeparator(char groupingSeparator) {
185+ this.groupingSeparator = groupingSeparator;
186+ }
187+
188+ /**
189+ * Gets the character used for decimal sign. Different for French, etc.
190+ */
191+ public char getDecimalSeparator() {
192+ return decimalSeparator;
193+ }
194+
195+ /**
196+ * Sets the character used for decimal sign. Different for French, etc.
197+ */
198+ public void setDecimalSeparator(char decimalSeparator) {
199+ this.decimalSeparator = decimalSeparator;
200+ }
201+
202+ /**
203+ * Gets the character used for per mille sign. Different for Arabic, etc.
204+ */
205+ public char getPerMill() {
206+ return perMill;
207+ }
208+
209+ /**
210+ * Sets the character used for per mille sign. Different for Arabic, etc.
211+ */
212+ public void setPerMill(char perMill) {
213+ this.perMill = perMill;
214+ }
215+
216+ /**
217+ * Gets the character used for percent sign. Different for Arabic, etc.
218+ */
219+ public char getPercent() {
220+ return percent;
221+ }
222+
223+ /**
224+ * Sets the character used for percent sign. Different for Arabic, etc.
225+ */
226+ public void setPercent(char percent) {
227+ this.percent = percent;
228+ }
229+
230+ /**
231+ * Gets the character used for a digit in a pattern.
232+ */
233+ public char getDigit() {
234+ return digit;
235+ }
236+
237+ /**
238+ * Sets the character used for a digit in a pattern.
239+ */
240+ public void setDigit(char digit) {
241+ this.digit = digit;
242+ }
243+
244+ /**
245+ * Gets the character used to separate positive and negative subpatterns
246+ * in a pattern.
247+ */
248+ public char getPatternSeparator() {
249+ return patternSeparator;
250+ }
251+
252+ /**
253+ * Sets the character used to separate positive and negative subpatterns
254+ * in a pattern.
255+ */
256+ public void setPatternSeparator(char patternSeparator) {
257+ this.patternSeparator = patternSeparator;
258+ }
259+
260+ /**
261+ * Gets the string used to represent infinity. Almost always left
262+ * unchanged.
263+ */
264+ public String getInfinity() {
265+ return infinity;
266+ }
267+
268+ /**
269+ * Sets the string used to represent infinity. Almost always left
270+ * unchanged.
271+ */
272+ public void setInfinity(String infinity) {
273+ this.infinity = infinity;
274+ }
275+
276+ /**
277+ * Gets the string used to represent "not a number". Almost always left
278+ * unchanged.
279+ */
280+ public String getNaN() {
281+ return NaN;
282+ }
283+
284+ /**
285+ * Sets the string used to represent "not a number". Almost always left
286+ * unchanged.
287+ */
288+ public void setNaN(String NaN) {
289+ this.NaN = NaN;
290+ }
291+
292+ /**
293+ * Gets the character used to represent minus sign. If no explicit
294+ * negative format is specified, one is formed by prefixing
295+ * minusSign to the positive format.
296+ */
297+ public char getMinusSign() {
298+ return minusSign;
299+ }
300+
301+ /**
302+ * Sets the character used to represent minus sign. If no explicit
303+ * negative format is specified, one is formed by prefixing
304+ * minusSign to the positive format.
305+ */
306+ public void setMinusSign(char minusSign) {
307+ this.minusSign = minusSign;
308+ }
309+
310+ /**
311+ * Returns the currency symbol for the currency of these
312+ * DecimalFormatSymbols in their locale.
313+ * @since 1.2
314+ */
315+ public String getCurrencySymbol()
316+ {
317+ return currencySymbol;
318+ }
319+
320+ /**
321+ * Sets the currency symbol for the currency of these
322+ * DecimalFormatSymbols in their locale.
323+ * @since 1.2
324+ */
325+ public void setCurrencySymbol(String currency)
326+ {
327+ currencySymbol = currency;
328+ }
329+
330+ /**
331+ * Returns the ISO 4217 currency code of the currency of these
332+ * DecimalFormatSymbols.
333+ * @since 1.2
334+ */
335+ public String getInternationalCurrencySymbol()
336+ {
337+ return intlCurrencySymbol;
338+ }
339+
340+ /**
341+ * Sets the ISO 4217 currency code of the currency of these
342+ * DecimalFormatSymbols.
343+ * If the currency code is valid (as defined by
344+ * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
345+ * this also sets the currency attribute to the corresponding Currency
346+ * instance and the currency symbol attribute to the currency's symbol
347+ * in the DecimalFormatSymbols' locale. If the currency code is not valid,
348+ * then the currency attribute is set to null and the currency symbol
349+ * attribute is not modified.
350+ *
351+ * @see #setCurrency
352+ * @see #setCurrencySymbol
353+ * @since 1.2
354+ */
355+ public void setInternationalCurrencySymbol(String currencyCode)
356+ {
357+ intlCurrencySymbol = currencyCode;
358+ currency = null;
359+ if (currencyCode != null) {
360+ try {
361+ currency = Currency.getInstance(currencyCode);
362+ currencySymbol = currency.getSymbol();
363+ } catch (IllegalArgumentException e) {
364+ }
365+ }
366+ }
367+
368+ /**
369+ * Gets the currency of these DecimalFormatSymbols. May be null if the
370+ * currency symbol attribute was previously set to a value that's not
371+ * a valid ISO 4217 currency code.
372+ *
373+ * @return the currency used, or null
374+ * @since 1.4
375+ */
376+ public Currency getCurrency() {
377+ return currency;
378+ }
379+
380+ /**
381+ * Sets the currency of these DecimalFormatSymbols.
382+ * This also sets the currency symbol attribute to the currency's symbol
383+ * in the DecimalFormatSymbols' locale, and the international currency
384+ * symbol attribute to the currency's ISO 4217 currency code.
385+ *
386+ * @param currency the new currency to be used
387+ * @exception NullPointerException if <code>currency</code> is null
388+ * @since 1.4
389+ * @see #setCurrencySymbol
390+ * @see #setInternationalCurrencySymbol
391+ */
392+ public void setCurrency(Currency currency) {
393+ if (currency == null) {
394+ throw new NullPointerException();
395+ }
396+ this.currency = currency;
397+ intlCurrencySymbol = currency.getCurrencyCode();
398+ currencySymbol = currency.getSymbol(locale);
399+ }
400+
401+
402+ /**
403+ * Returns the monetary decimal separator.
404+ * @since 1.2
405+ */
406+ public char getMonetaryDecimalSeparator()
407+ {
408+ return monetarySeparator;
409+ }
410+
411+ /**
412+ * Sets the monetary decimal separator.
413+ * @since 1.2
414+ */
415+ public void setMonetaryDecimalSeparator(char sep)
416+ {
417+ monetarySeparator = sep;
418+ }
419+
420+ //------------------------------------------------------------
421+ // BEGIN Package Private methods ... to be made public later
422+ //------------------------------------------------------------
423+
424+ /**
425+ * Returns the character used to separate the mantissa from the exponent.
426+ */
427+ char getExponentialSymbol()
428+ {
429+ return exponential;
430+ }
431+ /**
432+ * Returns the string used to separate the mantissa from the exponent.
433+ * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
434+ *
435+ * @return the exponent separator string
436+ * @see #setExponentSeparator(java.lang.String)
437+ * @since 1.6
438+ */
439+ public String getExponentSeparator()
440+ {
441+ return exponentialSeparator;
442+ }
443+
444+ /**
445+ * Sets the character used to separate the mantissa from the exponent.
446+ */
447+ void setExponentialSymbol(char exp)
448+ {
449+ exponential = exp;
450+ }
451+
452+ /**
453+ * Sets the string used to separate the mantissa from the exponent.
454+ * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
455+ *
456+ * @param exp the exponent separator string
457+ * @exception NullPointerException if <code>exp</code> is null
458+ * @see #getExponentSeparator()
459+ * @since 1.6
460+ */
461+ public void setExponentSeparator(String exp)
462+ {
463+ if (exp == null) {
464+ throw new NullPointerException();
465+ }
466+ exponentialSeparator = exp;
467+ }
468+
469+
470+ //------------------------------------------------------------
471+ // END Package Private methods ... to be made public later
472+ //------------------------------------------------------------
473+
474+ /**
475+ * Standard override.
476+ */
477+ public Object clone() {
478+ try {
479+ return (DecimalFormatSymbols)super.clone();
480+ // other fields are bit-copied
481+ } catch (CloneNotSupportedException e) {
482+ throw new InternalError();
483+ }
484+ }
485+
486+ /**
487+ * Override equals.
488+ */
489+ public boolean equals(Object obj) {
490+ if (obj == null) return false;
491+ if (this == obj) return true;
492+ if (getClass() != obj.getClass()) return false;
493+ DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
494+ return (zeroDigit == other.zeroDigit &&
495+ groupingSeparator == other.groupingSeparator &&
496+ decimalSeparator == other.decimalSeparator &&
497+ percent == other.percent &&
498+ perMill == other.perMill &&
499+ digit == other.digit &&
500+ minusSign == other.minusSign &&
501+ patternSeparator == other.patternSeparator &&
502+ infinity.equals(other.infinity) &&
503+ NaN.equals(other.NaN) &&
504+ currencySymbol.equals(other.currencySymbol) &&
505+ intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
506+ currency == other.currency &&
507+ monetarySeparator == other.monetarySeparator &&
508+ exponentialSeparator.equals(other.exponentialSeparator) &&
509+ locale.equals(other.locale));
510+ }
511+
512+ /**
513+ * Override hashCode.
514+ */
515+ public int hashCode() {
516+ int result = zeroDigit;
517+ result = result * 37 + groupingSeparator;
518+ result = result * 37 + decimalSeparator;
519+ return result;
520+ }
521+
522+ /**
523+ * Initializes the symbols from the FormatData resource bundle.
524+ */
525+ private void initialize( Locale locale ) {
526+ this.locale = locale;
527+
528+ // get resource bundle data - try the cache first
529+ boolean needCacheUpdate = false;
530+ Object[] data = cachedLocaleData.get(locale);
531+ if (data == null) { /* cache miss */
532+ // When numbering system is thai (Locale's extension contains u-nu-thai),
533+ // we read the data from th_TH_TH.
534+ Locale lookupLocale = locale;
535+ String numberType = locale.getUnicodeLocaleType("nu");
536+ if (numberType != null && numberType.equals("thai")) {
537+ lookupLocale = new Locale("th", "TH", "TH");
538+ }
539+ data = new Object[3];
540+ ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
541+ data[0] = rb.getStringArray("NumberElements");
542+ needCacheUpdate = true;
543+ }
544+
545+ String[] numberElements = (String[]) data[0];
546+
547+ decimalSeparator = numberElements[0].charAt(0);
548+ groupingSeparator = numberElements[1].charAt(0);
549+ patternSeparator = numberElements[2].charAt(0);
550+ percent = numberElements[3].charAt(0);
551+ zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
552+ digit = numberElements[5].charAt(0);
553+ minusSign = numberElements[6].charAt(0);
554+ exponential = numberElements[7].charAt(0);
555+ exponentialSeparator = numberElements[7]; //string representation new since 1.6
556+ perMill = numberElements[8].charAt(0);
557+ infinity = numberElements[9];
558+ NaN = numberElements[10];
559+
560+ // Try to obtain the currency used in the locale's country.
561+ // Check for empty country string separately because it's a valid
562+ // country ID for Locale (and used for the C locale), but not a valid
563+ // ISO 3166 country code, and exceptions are expensive.
564+ if (!"".equals(locale.getCountry())) {
565+ try {
566+ currency = Currency.getInstance(locale);
567+ } catch (IllegalArgumentException e) {
568+ // use default values below for compatibility
569+ }
570+ }
571+ if (currency != null) {
572+ intlCurrencySymbol = currency.getCurrencyCode();
573+ if (data[1] != null && data[1] == intlCurrencySymbol) {
574+ currencySymbol = (String) data[2];
575+ } else {
576+ currencySymbol = currency.getSymbol(locale);
577+ data[1] = intlCurrencySymbol;
578+ data[2] = currencySymbol;
579+ needCacheUpdate = true;
580+ }
581+ } else {
582+ // default values
583+ intlCurrencySymbol = "XXX";
584+ try {
585+ currency = Currency.getInstance(intlCurrencySymbol);
586+ } catch (IllegalArgumentException e) {
587+ }
588+ currencySymbol = "\u00A4";
589+ }
590+ // Currently the monetary decimal separator is the same as the
591+ // standard decimal separator for all locales that we support.
592+ // If that changes, add a new entry to NumberElements.
593+ monetarySeparator = decimalSeparator;
594+
595+ if (needCacheUpdate) {
596+ cachedLocaleData.putIfAbsent(locale, data);
597+ }
598+ }
599+
600+ /**
601+ * Reads the default serializable fields, provides default values for objects
602+ * in older serial versions, and initializes non-serializable fields.
603+ * If <code>serialVersionOnStream</code>
604+ * is less than 1, initializes <code>monetarySeparator</code> to be
605+ * the same as <code>decimalSeparator</code> and <code>exponential</code>
606+ * to be 'E'.
607+ * If <code>serialVersionOnStream</code> is less than 2,
608+ * initializes <code>locale</code>to the root locale, and initializes
609+ * If <code>serialVersionOnStream</code> is less than 3, it initializes
610+ * <code>exponentialSeparator</code> using <code>exponential</code>.
611+ * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
612+ * default serialization will work properly if this object is streamed out again.
613+ * Initializes the currency from the intlCurrencySymbol field.
614+ *
615+ * @since JDK 1.1.6
616+ */
617+ private void readObject(ObjectInputStream stream)
618+ throws IOException, ClassNotFoundException {
619+ stream.defaultReadObject();
620+ if (serialVersionOnStream < 1) {
621+ // Didn't have monetarySeparator or exponential field;
622+ // use defaults.
623+ monetarySeparator = decimalSeparator;
624+ exponential = 'E';
625+ }
626+ if (serialVersionOnStream < 2) {
627+ // didn't have locale; use root locale
628+ locale = Locale.ROOT;
629+ }
630+ if (serialVersionOnStream < 3) {
631+ // didn't have exponentialSeparator. Create one using exponential
632+ exponentialSeparator = Character.toString(exponential);
633+ }
634+ serialVersionOnStream = currentSerialVersion;
635+
636+ if (intlCurrencySymbol != null) {
637+ try {
638+ currency = Currency.getInstance(intlCurrencySymbol);
639+ } catch (IllegalArgumentException e) {
640+ }
641+ }
642+ }
643+
644+ /**
645+ * Character used for zero.
646+ *
647+ * @serial
648+ * @see #getZeroDigit
649+ */
650+ private char zeroDigit;
651+
652+ /**
653+ * Character used for thousands separator.
654+ *
655+ * @serial
656+ * @see #getGroupingSeparator
657+ */
658+ private char groupingSeparator;
659+
660+ /**
661+ * Character used for decimal sign.
662+ *
663+ * @serial
664+ * @see #getDecimalSeparator
665+ */
666+ private char decimalSeparator;
667+
668+ /**
669+ * Character used for per mille sign.
670+ *
671+ * @serial
672+ * @see #getPerMill
673+ */
674+ private char perMill;
675+
676+ /**
677+ * Character used for percent sign.
678+ * @serial
679+ * @see #getPercent
680+ */
681+ private char percent;
682+
683+ /**
684+ * Character used for a digit in a pattern.
685+ *
686+ * @serial
687+ * @see #getDigit
688+ */
689+ private char digit;
690+
691+ /**
692+ * Character used to separate positive and negative subpatterns
693+ * in a pattern.
694+ *
695+ * @serial
696+ * @see #getPatternSeparator
697+ */
698+ private char patternSeparator;
699+
700+ /**
701+ * String used to represent infinity.
702+ * @serial
703+ * @see #getInfinity
704+ */
705+ private String infinity;
706+
707+ /**
708+ * String used to represent "not a number".
709+ * @serial
710+ * @see #getNaN
711+ */
712+ private String NaN;
713+
714+ /**
715+ * Character used to represent minus sign.
716+ * @serial
717+ * @see #getMinusSign
718+ */
719+ private char minusSign;
720+
721+ /**
722+ * String denoting the local currency, e.g. "$".
723+ * @serial
724+ * @see #getCurrencySymbol
725+ */
726+ private String currencySymbol;
727+
728+ /**
729+ * ISO 4217 currency code denoting the local currency, e.g. "USD".
730+ * @serial
731+ * @see #getInternationalCurrencySymbol
732+ */
733+ private String intlCurrencySymbol;
734+
735+ /**
736+ * The decimal separator used when formatting currency values.
737+ * @serial
738+ * @since JDK 1.1.6
739+ * @see #getMonetaryDecimalSeparator
740+ */
741+ private char monetarySeparator; // Field new in JDK 1.1.6
742+
743+ /**
744+ * The character used to distinguish the exponent in a number formatted
745+ * in exponential notation, e.g. 'E' for a number such as "1.23E45".
746+ * <p>
747+ * Note that the public API provides no way to set this field,
748+ * even though it is supported by the implementation and the stream format.
749+ * The intent is that this will be added to the API in the future.
750+ *
751+ * @serial
752+ * @since JDK 1.1.6
753+ */
754+ private char exponential; // Field new in JDK 1.1.6
755+
756+ /**
757+ * The string used to separate the mantissa from the exponent.
758+ * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
759+ * <p>
760+ * If both <code>exponential</code> and <code>exponentialSeparator</code>
761+ * exist, this <code>exponentialSeparator</code> has the precedence.
762+ *
763+ * @serial
764+ * @since 1.6
765+ */
766+ private String exponentialSeparator; // Field new in JDK 1.6
767+
768+ /**
769+ * The locale of these currency format symbols.
770+ *
771+ * @serial
772+ * @since 1.4
773+ */
774+ private Locale locale;
775+
776+ // currency; only the ISO code is serialized.
777+ private transient Currency currency;
778+
779+ // Proclaim JDK 1.1 FCS compatibility
780+ static final long serialVersionUID = 5772796243397350300L;
781+
782+ // The internal serial version which says which version was written
783+ // - 0 (default) for version up to JDK 1.1.5
784+ // - 1 for version from JDK 1.1.6, which includes two new fields:
785+ // monetarySeparator and exponential.
786+ // - 2 for version from J2SE 1.4, which includes locale field.
787+ // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
788+ private static final int currentSerialVersion = 3;
789+
790+ /**
791+ * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
792+ * Possible values are:
793+ * <ul>
794+ * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
795+ *
796+ * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
797+ * two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
798+ * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
799+ * new <code>locale</code> field.
800+ * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
801+ * new <code>exponentialSeparator</code> field.
802+ * </ul>
803+ * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
804+ * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
805+ * is always written.
806+ *
807+ * @serial
808+ * @since JDK 1.1.6
809+ */
810+ private int serialVersionOnStream = currentSerialVersion;
811+
812+ /**
813+ * cache to hold the NumberElements and the Currency
814+ * of a Locale.
815+ */
816+ private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
817+
818+ /**
819+ * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
820+ * implementation.
821+ */
822+ private static class DecimalFormatSymbolsGetter
823+ implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
824+ DecimalFormatSymbols> {
825+ private static final DecimalFormatSymbolsGetter INSTANCE =
826+ new DecimalFormatSymbolsGetter();
827+
828+ public DecimalFormatSymbols getObject(
829+ DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
830+ Locale locale,
831+ String key,
832+ Object... params) {
833+ assert params.length == 0;
834+ return decimalFormatSymbolsProvider.getInstance(locale);
835+ }
836+ }
837+}
java/pkg/java/text/DictionaryBasedBreakIterator.class+0−0

Binary file not shown.

java/pkg/java/text/DictionaryBasedBreakIterator.java+514−0
@@ -0,0 +1,514 @@
1+/*
2+ * Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ *
28+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
29+ * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved
30+ *
31+ * The original version of this source code and documentation
32+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
33+ * subsidiary of IBM. These materials are provided under terms
34+ * of a License Agreement between Taligent and Sun. This technology
35+ * is protected by multiple US and International patents.
36+ *
37+ * This notice and attribution to Taligent may not be removed.
38+ * Taligent is a registered trademark of Taligent, Inc.
39+ */
40+
41+package java.text;
42+
43+import java.util.Vector;
44+import java.util.Stack;
45+import java.util.Hashtable;
46+import java.text.CharacterIterator;
47+import java.io.InputStream;
48+import java.io.IOException;
49+
50+/**
51+ * A subclass of RuleBasedBreakIterator that adds the ability to use a dictionary
52+ * to further subdivide ranges of text beyond what is possible using just the
53+ * state-table-based algorithm. This is necessary, for example, to handle
54+ * word and line breaking in Thai, which doesn't use spaces between words. The
55+ * state-table-based algorithm used by RuleBasedBreakIterator is used to divide
56+ * up text as far as possible, and then contiguous ranges of letters are
57+ * repeatedly compared against a list of known words (i.e., the dictionary)
58+ * to divide them up into words.
59+ *
60+ * DictionaryBasedBreakIterator uses the same rule language as RuleBasedBreakIterator,
61+ * but adds one more special substitution name: &lt;dictionary&gt;. This substitution
62+ * name is used to identify characters in words in the dictionary. The idea is that
63+ * if the iterator passes over a chunk of text that includes two or more characters
64+ * in a row that are included in &lt;dictionary&gt;, it goes back through that range and
65+ * derives additional break positions (if possible) using the dictionary.
66+ *
67+ * DictionaryBasedBreakIterator is also constructed with the filename of a dictionary
68+ * file. It follows a prescribed search path to locate the dictionary (right now,
69+ * it looks for it in /com/ibm/text/resources in each directory in the classpath,
70+ * and won't find it in JAR files, but this location is likely to change). The
71+ * dictionary file is in a serialized binary format. We have a very primitive (and
72+ * slow) BuildDictionaryFile utility for creating dictionary files, but aren't
73+ * currently making it public. Contact us for help.
74+ */
75+class DictionaryBasedBreakIterator extends RuleBasedBreakIterator {
76+
77+ /**
78+ * a list of known words that is used to divide up contiguous ranges of letters,
79+ * stored in a compressed, indexed, format that offers fast access
80+ */
81+ private BreakDictionary dictionary;
82+
83+ /**
84+ * a list of flags indicating which character categories are contained in
85+ * the dictionary file (this is used to determine which ranges of characters
86+ * to apply the dictionary to)
87+ */
88+ private boolean[] categoryFlags;
89+
90+ /**
91+ * a temporary hiding place for the number of dictionary characters in the
92+ * last range passed over by next()
93+ */
94+ private int dictionaryCharCount;
95+
96+ /**
97+ * when a range of characters is divided up using the dictionary, the break
98+ * positions that are discovered are stored here, preventing us from having
99+ * to use either the dictionary or the state table again until the iterator
100+ * leaves this range of text
101+ */
102+ private int[] cachedBreakPositions;
103+
104+ /**
105+ * if cachedBreakPositions is not null, this indicates which item in the
106+ * cache the current iteration position refers to
107+ */
108+ private int positionInCache;
109+
110+ /**
111+ * Constructs a DictionaryBasedBreakIterator.
112+ * @param description Same as the description parameter on RuleBasedBreakIterator,
113+ * except for the special meaning of "<dictionary>". This parameter is just
114+ * passed through to RuleBasedBreakIterator's constructor.
115+ * @param dictionaryFilename The filename of the dictionary file to use
116+ */
117+ public DictionaryBasedBreakIterator(String dataFile, String dictionaryFile)
118+ throws IOException {
119+ super(dataFile);
120+ byte[] tmp = super.getAdditionalData();
121+ if (tmp != null) {
122+ prepareCategoryFlags(tmp);
123+ super.setAdditionalData(null);
124+ }
125+ dictionary = new BreakDictionary(dictionaryFile);
126+ }
127+
128+ private void prepareCategoryFlags(byte[] data) {
129+ categoryFlags = new boolean[data.length];
130+ for (int i = 0; i < data.length; i++) {
131+ categoryFlags[i] = (data[i] == (byte)1) ? true : false;
132+ }
133+ }
134+
135+ public void setText(CharacterIterator newText) {
136+ super.setText(newText);
137+ cachedBreakPositions = null;
138+ dictionaryCharCount = 0;
139+ positionInCache = 0;
140+ }
141+
142+ /**
143+ * Sets the current iteration position to the beginning of the text.
144+ * (i.e., the CharacterIterator's starting offset).
145+ * @return The offset of the beginning of the text.
146+ */
147+ public int first() {
148+ cachedBreakPositions = null;
149+ dictionaryCharCount = 0;
150+ positionInCache = 0;
151+ return super.first();
152+ }
153+
154+ /**
155+ * Sets the current iteration position to the end of the text.
156+ * (i.e., the CharacterIterator's ending offset).
157+ * @return The text's past-the-end offset.
158+ */
159+ public int last() {
160+ cachedBreakPositions = null;
161+ dictionaryCharCount = 0;
162+ positionInCache = 0;
163+ return super.last();
164+ }
165+
166+ /**
167+ * Advances the iterator one step backwards.
168+ * @return The position of the last boundary position before the
169+ * current iteration position
170+ */
171+ public int previous() {
172+ CharacterIterator text = getText();
173+
174+ // if we have cached break positions and we're still in the range
175+ // covered by them, just move one step backward in the cache
176+ if (cachedBreakPositions != null && positionInCache > 0) {
177+ --positionInCache;
178+ text.setIndex(cachedBreakPositions[positionInCache]);
179+ return cachedBreakPositions[positionInCache];
180+ }
181+
182+ // otherwise, dump the cache and use the inherited previous() method to move
183+ // backward. This may fill up the cache with new break positions, in which
184+ // case we have to mark our position in the cache
185+ else {
186+ cachedBreakPositions = null;
187+ int result = super.previous();
188+ if (cachedBreakPositions != null) {
189+ positionInCache = cachedBreakPositions.length - 2;
190+ }
191+ return result;
192+ }
193+ }
194+
195+ /**
196+ * Sets the current iteration position to the last boundary position
197+ * before the specified position.
198+ * @param offset The position to begin searching from
199+ * @return The position of the last boundary before "offset"
200+ */
201+ public int preceding(int offset) {
202+ CharacterIterator text = getText();
203+ checkOffset(offset, text);
204+
205+ // if we have no cached break positions, or "offset" is outside the
206+ // range covered by the cache, we can just call the inherited routine
207+ // (which will eventually call other routines in this class that may
208+ // refresh the cache)
209+ if (cachedBreakPositions == null || offset <= cachedBreakPositions[0] ||
210+ offset > cachedBreakPositions[cachedBreakPositions.length - 1]) {
211+ cachedBreakPositions = null;
212+ return super.preceding(offset);
213+ }
214+
215+ // on the other hand, if "offset" is within the range covered by the cache,
216+ // then all we have to do is search the cache for the last break position
217+ // before "offset"
218+ else {
219+ positionInCache = 0;
220+ while (positionInCache < cachedBreakPositions.length
221+ && offset > cachedBreakPositions[positionInCache]) {
222+ ++positionInCache;
223+ }
224+ --positionInCache;
225+ text.setIndex(cachedBreakPositions[positionInCache]);
226+ return text.getIndex();
227+ }
228+ }
229+
230+ /**
231+ * Sets the current iteration position to the first boundary position after
232+ * the specified position.
233+ * @param offset The position to begin searching forward from
234+ * @return The position of the first boundary after "offset"
235+ */
236+ public int following(int offset) {
237+ CharacterIterator text = getText();
238+ checkOffset(offset, text);
239+
240+ // if we have no cached break positions, or if "offset" is outside the
241+ // range covered by the cache, then dump the cache and call our
242+ // inherited following() method. This will call other methods in this
243+ // class that may refresh the cache.
244+ if (cachedBreakPositions == null || offset < cachedBreakPositions[0] ||
245+ offset >= cachedBreakPositions[cachedBreakPositions.length - 1]) {
246+ cachedBreakPositions = null;
247+ return super.following(offset);
248+ }
249+
250+ // on the other hand, if "offset" is within the range covered by the
251+ // cache, then just search the cache for the first break position
252+ // after "offset"
253+ else {
254+ positionInCache = 0;
255+ while (positionInCache < cachedBreakPositions.length
256+ && offset >= cachedBreakPositions[positionInCache]) {
257+ ++positionInCache;
258+ }
259+ text.setIndex(cachedBreakPositions[positionInCache]);
260+ return text.getIndex();
261+ }
262+ }
263+
264+ /**
265+ * This is the implementation function for next().
266+ */
267+ protected int handleNext() {
268+ CharacterIterator text = getText();
269+
270+ // if there are no cached break positions, or if we've just moved
271+ // off the end of the range covered by the cache, we have to dump
272+ // and possibly regenerate the cache
273+ if (cachedBreakPositions == null ||
274+ positionInCache == cachedBreakPositions.length - 1) {
275+
276+ // start by using the inherited handleNext() to find a tentative return
277+ // value. dictionaryCharCount tells us how many dictionary characters
278+ // we passed over on our way to the tentative return value
279+ int startPos = text.getIndex();
280+ dictionaryCharCount = 0;
281+ int result = super.handleNext();
282+
283+ // if we passed over more than one dictionary character, then we use
284+ // divideUpDictionaryRange() to regenerate the cached break positions
285+ // for the new range
286+ if (dictionaryCharCount > 1 && result - startPos > 1) {
287+ divideUpDictionaryRange(startPos, result);
288+ }
289+
290+ // otherwise, the value we got back from the inherited fuction
291+ // is our return value, and we can dump the cache
292+ else {
293+ cachedBreakPositions = null;
294+ return result;
295+ }
296+ }
297+
298+ // if the cache of break positions has been regenerated (or existed all
299+ // along), then just advance to the next break position in the cache
300+ // and return it
301+ if (cachedBreakPositions != null) {
302+ ++positionInCache;
303+ text.setIndex(cachedBreakPositions[positionInCache]);
304+ return cachedBreakPositions[positionInCache];
305+ }
306+ return -9999; // SHOULD NEVER GET HERE!
307+ }
308+
309+ /**
310+ * Looks up a character category for a character.
311+ */
312+ protected int lookupCategory(int c) {
313+ // this override of lookupCategory() exists only to keep track of whether we've
314+ // passed over any dictionary characters. It calls the inherited lookupCategory()
315+ // to do the real work, and then checks whether its return value is one of the
316+ // categories represented in the dictionary. If it is, bump the dictionary-
317+ // character count.
318+ int result = super.lookupCategory(c);
319+ if (result != RuleBasedBreakIterator.IGNORE && categoryFlags[result]) {
320+ ++dictionaryCharCount;
321+ }
322+ return result;
323+ }
324+
325+ /**
326+ * This is the function that actually implements the dictionary-based
327+ * algorithm. Given the endpoints of a range of text, it uses the
328+ * dictionary to determine the positions of any boundaries in this
329+ * range. It stores all the boundary positions it discovers in
330+ * cachedBreakPositions so that we only have to do this work once
331+ * for each time we enter the range.
332+ */
333+ private void divideUpDictionaryRange(int startPos, int endPos) {
334+ CharacterIterator text = getText();
335+
336+ // the range we're dividing may begin or end with non-dictionary characters
337+ // (i.e., for line breaking, we may have leading or trailing punctuation
338+ // that needs to be kept with the word). Seek from the beginning of the
339+ // range to the first dictionary character
340+ text.setIndex(startPos);
341+ int c = getCurrent();
342+ int category = lookupCategory(c);
343+ while (category == IGNORE || !categoryFlags[category]) {
344+ c = getNext();
345+ category = lookupCategory(c);
346+ }
347+
348+ // initialize. We maintain two stacks: currentBreakPositions contains
349+ // the list of break positions that will be returned if we successfully
350+ // finish traversing the whole range now. possibleBreakPositions lists
351+ // all other possible word ends we've passed along the way. (Whenever
352+ // we reach an error [a sequence of characters that can't begin any word
353+ // in the dictionary], we back up, possibly delete some breaks from
354+ // currentBreakPositions, move a break from possibleBreakPositions
355+ // to currentBreakPositions, and start over from there. This process
356+ // continues in this way until we either successfully make it all the way
357+ // across the range, or exhaust all of our combinations of break
358+ // positions.)
359+ Stack currentBreakPositions = new Stack();
360+ Stack possibleBreakPositions = new Stack();
361+ Vector wrongBreakPositions = new Vector();
362+
363+ // the dictionary is implemented as a trie, which is treated as a state
364+ // machine. -1 represents the end of a legal word. Every word in the
365+ // dictionary is represented by a path from the root node to -1. A path
366+ // that ends in state 0 is an illegal combination of characters.
367+ int state = 0;
368+
369+ // these two variables are used for error handling. We keep track of the
370+ // farthest we've gotten through the range being divided, and the combination
371+ // of breaks that got us that far. If we use up all possible break
372+ // combinations, the text contains an error or a word that's not in the
373+ // dictionary. In this case, we "bless" the break positions that got us the
374+ // farthest as real break positions, and then start over from scratch with
375+ // the character where the error occurred.
376+ int farthestEndPoint = text.getIndex();
377+ Stack bestBreakPositions = null;
378+
379+ // initialize (we always exit the loop with a break statement)
380+ c = getCurrent();
381+ while (true) {
382+
383+ // if we can transition to state "-1" from our current state, we're
384+ // on the last character of a legal word. Push that position onto
385+ // the possible-break-positions stack
386+ if (dictionary.getNextState(state, 0) == -1) {
387+ possibleBreakPositions.push(Integer.valueOf(text.getIndex()));
388+ }
389+
390+ // look up the new state to transition to in the dictionary
391+ state = dictionary.getNextStateFromCharacter(state, c);
392+
393+ // if the character we're sitting on causes us to transition to
394+ // the "end of word" state, then it was a non-dictionary character
395+ // and we've successfully traversed the whole range. Drop out
396+ // of the loop.
397+ if (state == -1) {
398+ currentBreakPositions.push(Integer.valueOf(text.getIndex()));
399+ break;
400+ }
401+
402+ // if the character we're sitting on causes us to transition to
403+ // the error state, or if we've gone off the end of the range
404+ // without transitioning to the "end of word" state, we've hit
405+ // an error...
406+ else if (state == 0 || text.getIndex() >= endPos) {
407+
408+ // if this is the farthest we've gotten, take note of it in
409+ // case there's an error in the text
410+ if (text.getIndex() > farthestEndPoint) {
411+ farthestEndPoint = text.getIndex();
412+ bestBreakPositions = (Stack)(currentBreakPositions.clone());
413+ }
414+
415+ // wrongBreakPositions is a list of all break positions
416+ // we've tried starting that didn't allow us to traverse
417+ // all the way through the text. Every time we pop a
418+ //break position off of currentBreakPositions, we put it
419+ // into wrongBreakPositions to avoid trying it again later.
420+ // If we make it to this spot, we're either going to back
421+ // up to a break in possibleBreakPositions and try starting
422+ // over from there, or we've exhausted all possible break
423+ // positions and are going to do the fallback procedure.
424+ // This loop prevents us from messing with anything in
425+ // possibleBreakPositions that didn't work as a starting
426+ // point the last time we tried it (this is to prevent a bunch of
427+ // repetitive checks from slowing down some extreme cases)
428+ Integer newStartingSpot = null;
429+ while (!possibleBreakPositions.isEmpty() && wrongBreakPositions.contains(
430+ possibleBreakPositions.peek())) {
431+ possibleBreakPositions.pop();
432+ }
433+
434+ // if we've used up all possible break-position combinations, there's
435+ // an error or an unknown word in the text. In this case, we start
436+ // over, treating the farthest character we've reached as the beginning
437+ // of the range, and "blessing" the break positions that got us that
438+ // far as real break positions
439+ if (possibleBreakPositions.isEmpty()) {
440+ if (bestBreakPositions != null) {
441+ currentBreakPositions = bestBreakPositions;
442+ if (farthestEndPoint < endPos) {
443+ text.setIndex(farthestEndPoint + 1);
444+ }
445+ else {
446+ break;
447+ }
448+ }
449+ else {
450+ if ((currentBreakPositions.size() == 0 ||
451+ ((Integer)(currentBreakPositions.peek())).intValue() != text.getIndex())
452+ && text.getIndex() != startPos) {
453+ currentBreakPositions.push(new Integer(text.getIndex()));
454+ }
455+ getNext();
456+ currentBreakPositions.push(new Integer(text.getIndex()));
457+ }
458+ }
459+
460+ // if we still have more break positions we can try, then promote the
461+ // last break in possibleBreakPositions into currentBreakPositions,
462+ // and get rid of all entries in currentBreakPositions that come after
463+ // it. Then back up to that position and start over from there (i.e.,
464+ // treat that position as the beginning of a new word)
465+ else {
466+ Integer temp = (Integer)possibleBreakPositions.pop();
467+ Object temp2 = null;
468+ while (!currentBreakPositions.isEmpty() && temp.intValue() <
469+ ((Integer)currentBreakPositions.peek()).intValue()) {
470+ temp2 = currentBreakPositions.pop();
471+ wrongBreakPositions.addElement(temp2);
472+ }
473+ currentBreakPositions.push(temp);
474+ text.setIndex(((Integer)currentBreakPositions.peek()).intValue());
475+ }
476+
477+ // re-sync "c" for the next go-round, and drop out of the loop if
478+ // we've made it off the end of the range
479+ c = getCurrent();
480+ if (text.getIndex() >= endPos) {
481+ break;
482+ }
483+ }
484+
485+ // if we didn't hit any exceptional conditions on this last iteration,
486+ // just advance to the next character and loop
487+ else {
488+ c = getNext();
489+ }
490+ }
491+
492+ // dump the last break position in the list, and replace it with the actual
493+ // end of the range (which may be the same character, or may be further on
494+ // because the range actually ended with non-dictionary characters we want to
495+ // keep with the word)
496+ if (!currentBreakPositions.isEmpty()) {
497+ currentBreakPositions.pop();
498+ }
499+ currentBreakPositions.push(Integer.valueOf(endPos));
500+
501+ // create a regular array to hold the break positions and copy
502+ // the break positions from the stack to the array (in addition,
503+ // our starting position goes into this array as a break position).
504+ // This array becomes the cache of break positions used by next()
505+ // and previous(), so this is where we actually refresh the cache.
506+ cachedBreakPositions = new int[currentBreakPositions.size() + 1];
507+ cachedBreakPositions[0] = startPos;
508+
509+ for (int i = 0; i < currentBreakPositions.size(); i++) {
510+ cachedBreakPositions[i + 1] = ((Integer)currentBreakPositions.elementAt(i)).intValue();
511+ }
512+ positionInCache = 0;
513+ }
514+}
java/pkg/java/text/DigitList$1.class+0−0

Binary file not shown.

java/pkg/java/text/DigitList.class+0−0

Binary file not shown.

java/pkg/java/text/DigitList.java+715−0
@@ -0,0 +1,715 @@
1+/*
2+ * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.math.BigDecimal;
42+import java.math.BigInteger;
43+import java.math.RoundingMode;
44+
45+/**
46+ * Digit List. Private to DecimalFormat.
47+ * Handles the transcoding
48+ * between numeric values and strings of characters. Only handles
49+ * non-negative numbers. The division of labor between DigitList and
50+ * DecimalFormat is that DigitList handles the radix 10 representation
51+ * issues; DecimalFormat handles the locale-specific issues such as
52+ * positive/negative, grouping, decimal point, currency, and so on.
53+ *
54+ * A DigitList is really a representation of a floating point value.
55+ * It may be an integer value; we assume that a double has sufficient
56+ * precision to represent all digits of a long.
57+ *
58+ * The DigitList representation consists of a string of characters,
59+ * which are the digits radix 10, from '0' to '9'. It also has a radix
60+ * 10 exponent associated with it. The value represented by a DigitList
61+ * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
62+ * derived by placing all the digits of the list to the right of the
63+ * decimal point, by 10^exponent.
64+ *
65+ * @see Locale
66+ * @see Format
67+ * @see NumberFormat
68+ * @see DecimalFormat
69+ * @see ChoiceFormat
70+ * @see MessageFormat
71+ * @author Mark Davis, Alan Liu
72+ */
73+final class DigitList implements Cloneable {
74+ /**
75+ * The maximum number of significant digits in an IEEE 754 double, that
76+ * is, in a Java double. This must not be increased, or garbage digits
77+ * will be generated, and should not be decreased, or accuracy will be lost.
78+ */
79+ public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
80+
81+ /**
82+ * These data members are intentionally public and can be set directly.
83+ *
84+ * The value represented is given by placing the decimal point before
85+ * digits[decimalAt]. If decimalAt is < 0, then leading zeros between
86+ * the decimal point and the first nonzero digit are implied. If decimalAt
87+ * is > count, then trailing zeros between the digits[count-1] and the
88+ * decimal point are implied.
89+ *
90+ * Equivalently, the represented value is given by f * 10^decimalAt. Here
91+ * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
92+ * the right of the decimal.
93+ *
94+ * DigitList is normalized, so if it is non-zero, figits[0] is non-zero. We
95+ * don't allow denormalized numbers because our exponent is effectively of
96+ * unlimited magnitude. The count value contains the number of significant
97+ * digits present in digits[].
98+ *
99+ * Zero is represented by any DigitList with count == 0 or with each digits[i]
100+ * for all i <= count == '0'.
101+ */
102+ public int decimalAt = 0;
103+ public int count = 0;
104+ public char[] digits = new char[MAX_COUNT];
105+
106+ private char[] data;
107+ private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
108+ private boolean isNegative = false;
109+
110+ /**
111+ * Return true if the represented number is zero.
112+ */
113+ boolean isZero() {
114+ for (int i=0; i < count; ++i) {
115+ if (digits[i] != '0') {
116+ return false;
117+ }
118+ }
119+ return true;
120+ }
121+
122+ /**
123+ * Set the rounding mode
124+ */
125+ void setRoundingMode(RoundingMode r) {
126+ roundingMode = r;
127+ }
128+
129+ /**
130+ * Clears out the digits.
131+ * Use before appending them.
132+ * Typically, you set a series of digits with append, then at the point
133+ * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
134+ * then go on appending digits.
135+ */
136+ public void clear () {
137+ decimalAt = 0;
138+ count = 0;
139+ }
140+
141+ /**
142+ * Appends a digit to the list, extending the list when necessary.
143+ */
144+ public void append(char digit) {
145+ if (count == digits.length) {
146+ char[] data = new char[count + 100];
147+ System.arraycopy(digits, 0, data, 0, count);
148+ digits = data;
149+ }
150+ digits[count++] = digit;
151+ }
152+
153+ /**
154+ * Utility routine to get the value of the digit list
155+ * If (count == 0) this throws a NumberFormatException, which
156+ * mimics Long.parseLong().
157+ */
158+ public final double getDouble() {
159+ if (count == 0) {
160+ return 0.0;
161+ }
162+
163+ StringBuffer temp = getStringBuffer();
164+ temp.append('.');
165+ temp.append(digits, 0, count);
166+ temp.append('E');
167+ temp.append(decimalAt);
168+ return Double.parseDouble(temp.toString());
169+ }
170+
171+ /**
172+ * Utility routine to get the value of the digit list.
173+ * If (count == 0) this returns 0, unlike Long.parseLong().
174+ */
175+ public final long getLong() {
176+ // for now, simple implementation; later, do proper IEEE native stuff
177+
178+ if (count == 0) {
179+ return 0;
180+ }
181+
182+ // We have to check for this, because this is the one NEGATIVE value
183+ // we represent. If we tried to just pass the digits off to parseLong,
184+ // we'd get a parse failure.
185+ if (isLongMIN_VALUE()) {
186+ return Long.MIN_VALUE;
187+ }
188+
189+ StringBuffer temp = getStringBuffer();
190+ temp.append(digits, 0, count);
191+ for (int i = count; i < decimalAt; ++i) {
192+ temp.append('0');
193+ }
194+ return Long.parseLong(temp.toString());
195+ }
196+
197+ public final BigDecimal getBigDecimal() {
198+ if (count == 0) {
199+ if (decimalAt == 0) {
200+ return BigDecimal.ZERO;
201+ } else {
202+ return new BigDecimal("0E" + decimalAt);
203+ }
204+ }
205+
206+ if (decimalAt == count) {
207+ return new BigDecimal(digits, 0, count);
208+ } else {
209+ return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
210+ }
211+ }
212+
213+ /**
214+ * Return true if the number represented by this object can fit into
215+ * a long.
216+ * @param isPositive true if this number should be regarded as positive
217+ * @param ignoreNegativeZero true if -0 should be regarded as identical to
218+ * +0; otherwise they are considered distinct
219+ * @return true if this number fits into a Java long
220+ */
221+ boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
222+ // Figure out if the result will fit in a long. We have to
223+ // first look for nonzero digits after the decimal point;
224+ // then check the size. If the digit count is 18 or less, then
225+ // the value can definitely be represented as a long. If it is 19
226+ // then it may be too large.
227+
228+ // Trim trailing zeros. This does not change the represented value.
229+ while (count > 0 && digits[count - 1] == '0') {
230+ --count;
231+ }
232+
233+ if (count == 0) {
234+ // Positive zero fits into a long, but negative zero can only
235+ // be represented as a double. - bug 4162852
236+ return isPositive || ignoreNegativeZero;
237+ }
238+
239+ if (decimalAt < count || decimalAt > MAX_COUNT) {
240+ return false;
241+ }
242+
243+ if (decimalAt < MAX_COUNT) return true;
244+
245+ // At this point we have decimalAt == count, and count == MAX_COUNT.
246+ // The number will overflow if it is larger than 9223372036854775807
247+ // or smaller than -9223372036854775808.
248+ for (int i=0; i<count; ++i) {
249+ char dig = digits[i], max = LONG_MIN_REP[i];
250+ if (dig > max) return false;
251+ if (dig < max) return true;
252+ }
253+
254+ // At this point the first count digits match. If decimalAt is less
255+ // than count, then the remaining digits are zero, and we return true.
256+ if (count < decimalAt) return true;
257+
258+ // Now we have a representation of Long.MIN_VALUE, without the leading
259+ // negative sign. If this represents a positive value, then it does
260+ // not fit; otherwise it fits.
261+ return !isPositive;
262+ }
263+
264+ /**
265+ * Set the digit list to a representation of the given double value.
266+ * This method supports fixed-point notation.
267+ * @param isNegative Boolean value indicating whether the number is negative.
268+ * @param source Value to be converted; must not be Inf, -Inf, Nan,
269+ * or a value <= 0.
270+ * @param maximumFractionDigits The most fractional digits which should
271+ * be converted.
272+ */
273+ public final void set(boolean isNegative, double source, int maximumFractionDigits) {
274+ set(isNegative, source, maximumFractionDigits, true);
275+ }
276+
277+ /**
278+ * Set the digit list to a representation of the given double value.
279+ * This method supports both fixed-point and exponential notation.
280+ * @param isNegative Boolean value indicating whether the number is negative.
281+ * @param source Value to be converted; must not be Inf, -Inf, Nan,
282+ * or a value <= 0.
283+ * @param maximumDigits The most fractional or total digits which should
284+ * be converted.
285+ * @param fixedPoint If true, then maximumDigits is the maximum
286+ * fractional digits to be converted. If false, total digits.
287+ */
288+ final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
289+ set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
290+ }
291+
292+ /**
293+ * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
294+ * DDDDDE+/-DDDDD.
295+ */
296+ final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
297+ this.isNegative = isNegative;
298+ int len = s.length();
299+ char[] source = getDataChars(len);
300+ s.getChars(0, len, source, 0);
301+
302+ decimalAt = -1;
303+ count = 0;
304+ int exponent = 0;
305+ // Number of zeros between decimal point and first non-zero digit after
306+ // decimal point, for numbers < 1.
307+ int leadingZerosAfterDecimal = 0;
308+ boolean nonZeroDigitSeen = false;
309+
310+ for (int i = 0; i < len; ) {
311+ char c = source[i++];
312+ if (c == '.') {
313+ decimalAt = count;
314+ } else if (c == 'e' || c == 'E') {
315+ exponent = parseInt(source, i, len);
316+ break;
317+ } else {
318+ if (!nonZeroDigitSeen) {
319+ nonZeroDigitSeen = (c != '0');
320+ if (!nonZeroDigitSeen && decimalAt != -1)
321+ ++leadingZerosAfterDecimal;
322+ }
323+ if (nonZeroDigitSeen) {
324+ digits[count++] = c;
325+ }
326+ }
327+ }
328+ if (decimalAt == -1) {
329+ decimalAt = count;
330+ }
331+ if (nonZeroDigitSeen) {
332+ decimalAt += exponent - leadingZerosAfterDecimal;
333+ }
334+
335+ if (fixedPoint) {
336+ // The negative of the exponent represents the number of leading
337+ // zeros between the decimal and the first non-zero digit, for
338+ // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2). If this
339+ // is more than the maximum fraction digits, then we have an underflow
340+ // for the printed representation.
341+ if (-decimalAt > maximumDigits) {
342+ // Handle an underflow to zero when we round something like
343+ // 0.0009 to 2 fractional digits.
344+ count = 0;
345+ return;
346+ } else if (-decimalAt == maximumDigits) {
347+ // If we round 0.0009 to 3 fractional digits, then we have to
348+ // create a new one digit in the least significant location.
349+ if (shouldRoundUp(0)) {
350+ count = 1;
351+ ++decimalAt;
352+ digits[0] = '1';
353+ } else {
354+ count = 0;
355+ }
356+ return;
357+ }
358+ // else fall through
359+ }
360+
361+ // Eliminate trailing zeros.
362+ while (count > 1 && digits[count - 1] == '0') {
363+ --count;
364+ }
365+
366+ // Eliminate digits beyond maximum digits to be displayed.
367+ // Round up if appropriate.
368+ round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
369+ }
370+
371+ /**
372+ * Round the representation to the given number of digits.
373+ * @param maximumDigits The maximum number of digits to be shown.
374+ * Upon return, count will be less than or equal to maximumDigits.
375+ */
376+ private final void round(int maximumDigits) {
377+ // Eliminate digits beyond maximum digits to be displayed.
378+ // Round up if appropriate.
379+ if (maximumDigits >= 0 && maximumDigits < count) {
380+ if (shouldRoundUp(maximumDigits)) {
381+ // Rounding up involved incrementing digits from LSD to MSD.
382+ // In most cases this is simple, but in a worst case situation
383+ // (9999..99) we have to adjust the decimalAt value.
384+ for (;;) {
385+ --maximumDigits;
386+ if (maximumDigits < 0) {
387+ // We have all 9's, so we increment to a single digit
388+ // of one and adjust the exponent.
389+ digits[0] = '1';
390+ ++decimalAt;
391+ maximumDigits = 0; // Adjust the count
392+ break;
393+ }
394+
395+ ++digits[maximumDigits];
396+ if (digits[maximumDigits] <= '9') break;
397+ // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
398+ }
399+ ++maximumDigits; // Increment for use as count
400+ }
401+ count = maximumDigits;
402+
403+ // Eliminate trailing zeros.
404+ while (count > 1 && digits[count-1] == '0') {
405+ --count;
406+ }
407+ }
408+ }
409+
410+
411+ /**
412+ * Return true if truncating the representation to the given number
413+ * of digits will result in an increment to the last digit. This
414+ * method implements the rounding modes defined in the
415+ * java.math.RoundingMode class.
416+ * [bnf]
417+ * @param maximumDigits the number of digits to keep, from 0 to
418+ * <code>count-1</code>. If 0, then all digits are rounded away, and
419+ * this method returns true if a one should be generated (e.g., formatting
420+ * 0.09 with "#.#").
421+ * @exception ArithmeticException if rounding is needed with rounding
422+ * mode being set to RoundingMode.UNNECESSARY
423+ * @return true if digit <code>maximumDigits-1</code> should be
424+ * incremented
425+ */
426+ private boolean shouldRoundUp(int maximumDigits) {
427+ if (maximumDigits < count) {
428+ switch(roundingMode) {
429+ case UP:
430+ for (int i=maximumDigits; i<count; ++i) {
431+ if (digits[i] != '0') {
432+ return true;
433+ }
434+ }
435+ break;
436+ case DOWN:
437+ break;
438+ case CEILING:
439+ for (int i=maximumDigits; i<count; ++i) {
440+ if (digits[i] != '0') {
441+ return !isNegative;
442+ }
443+ }
444+ break;
445+ case FLOOR:
446+ for (int i=maximumDigits; i<count; ++i) {
447+ if (digits[i] != '0') {
448+ return isNegative;
449+ }
450+ }
451+ break;
452+ case HALF_UP:
453+ if (digits[maximumDigits] >= '5') {
454+ return true;
455+ }
456+ break;
457+ case HALF_DOWN:
458+ if (digits[maximumDigits] > '5') {
459+ return true;
460+ } else if (digits[maximumDigits] == '5' ) {
461+ for (int i=maximumDigits+1; i<count; ++i) {
462+ if (digits[i] != '0') {
463+ return true;
464+ }
465+ }
466+ }
467+ break;
468+ case HALF_EVEN:
469+ // Implement IEEE half-even rounding
470+ if (digits[maximumDigits] > '5') {
471+ return true;
472+ } else if (digits[maximumDigits] == '5' ) {
473+ for (int i=maximumDigits+1; i<count; ++i) {
474+ if (digits[i] != '0') {
475+ return true;
476+ }
477+ }
478+ return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
479+ }
480+ break;
481+ case UNNECESSARY:
482+ for (int i=maximumDigits; i<count; ++i) {
483+ if (digits[i] != '0') {
484+ throw new ArithmeticException(
485+ "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
486+ }
487+ }
488+ break;
489+ default:
490+ assert false;
491+ }
492+ }
493+ return false;
494+ }
495+
496+ /**
497+ * Utility routine to set the value of the digit list from a long
498+ */
499+ public final void set(boolean isNegative, long source) {
500+ set(isNegative, source, 0);
501+ }
502+
503+ /**
504+ * Set the digit list to a representation of the given long value.
505+ * @param isNegative Boolean value indicating whether the number is negative.
506+ * @param source Value to be converted; must be >= 0 or ==
507+ * Long.MIN_VALUE.
508+ * @param maximumDigits The most digits which should be converted.
509+ * If maximumDigits is lower than the number of significant digits
510+ * in source, the representation will be rounded. Ignored if <= 0.
511+ */
512+ public final void set(boolean isNegative, long source, int maximumDigits) {
513+ this.isNegative = isNegative;
514+
515+ // This method does not expect a negative number. However,
516+ // "source" can be a Long.MIN_VALUE (-9223372036854775808),
517+ // if the number being formatted is a Long.MIN_VALUE. In that
518+ // case, it will be formatted as -Long.MIN_VALUE, a number
519+ // which is outside the legal range of a long, but which can
520+ // be represented by DigitList.
521+ if (source <= 0) {
522+ if (source == Long.MIN_VALUE) {
523+ decimalAt = count = MAX_COUNT;
524+ System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
525+ } else {
526+ decimalAt = count = 0; // Values <= 0 format as zero
527+ }
528+ } else {
529+ // Rewritten to improve performance. I used to call
530+ // Long.toString(), which was about 4x slower than this code.
531+ int left = MAX_COUNT;
532+ int right;
533+ while (source > 0) {
534+ digits[--left] = (char)('0' + (source % 10));
535+ source /= 10;
536+ }
537+ decimalAt = MAX_COUNT - left;
538+ // Don't copy trailing zeros. We are guaranteed that there is at
539+ // least one non-zero digit, so we don't have to check lower bounds.
540+ for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
541+ ;
542+ count = right - left + 1;
543+ System.arraycopy(digits, left, digits, 0, count);
544+ }
545+ if (maximumDigits > 0) round(maximumDigits);
546+ }
547+
548+ /**
549+ * Set the digit list to a representation of the given BigDecimal value.
550+ * This method supports both fixed-point and exponential notation.
551+ * @param isNegative Boolean value indicating whether the number is negative.
552+ * @param source Value to be converted; must not be a value <= 0.
553+ * @param maximumDigits The most fractional or total digits which should
554+ * be converted.
555+ * @param fixedPoint If true, then maximumDigits is the maximum
556+ * fractional digits to be converted. If false, total digits.
557+ */
558+ final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
559+ String s = source.toString();
560+ extendDigits(s.length());
561+
562+ set(isNegative, s, maximumDigits, fixedPoint);
563+ }
564+
565+ /**
566+ * Set the digit list to a representation of the given BigInteger value.
567+ * @param isNegative Boolean value indicating whether the number is negative.
568+ * @param source Value to be converted; must be >= 0.
569+ * @param maximumDigits The most digits which should be converted.
570+ * If maximumDigits is lower than the number of significant digits
571+ * in source, the representation will be rounded. Ignored if <= 0.
572+ */
573+ final void set(boolean isNegative, BigInteger source, int maximumDigits) {
574+ this.isNegative = isNegative;
575+ String s = source.toString();
576+ int len = s.length();
577+ extendDigits(len);
578+ s.getChars(0, len, digits, 0);
579+
580+ decimalAt = len;
581+ int right;
582+ for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
583+ ;
584+ count = right + 1;
585+
586+ if (maximumDigits > 0) {
587+ round(maximumDigits);
588+ }
589+ }
590+
591+ /**
592+ * equality test between two digit lists.
593+ */
594+ public boolean equals(Object obj) {
595+ if (this == obj) // quick check
596+ return true;
597+ if (!(obj instanceof DigitList)) // (1) same object?
598+ return false;
599+ DigitList other = (DigitList) obj;
600+ if (count != other.count ||
601+ decimalAt != other.decimalAt)
602+ return false;
603+ for (int i = 0; i < count; i++)
604+ if (digits[i] != other.digits[i])
605+ return false;
606+ return true;
607+ }
608+
609+ /**
610+ * Generates the hash code for the digit list.
611+ */
612+ public int hashCode() {
613+ int hashcode = decimalAt;
614+
615+ for (int i = 0; i < count; i++) {
616+ hashcode = hashcode * 37 + digits[i];
617+ }
618+
619+ return hashcode;
620+ }
621+
622+ /**
623+ * Creates a copy of this object.
624+ * @return a clone of this instance.
625+ */
626+ public Object clone() {
627+ try {
628+ DigitList other = (DigitList) super.clone();
629+ char[] newDigits = new char[digits.length];
630+ System.arraycopy(digits, 0, newDigits, 0, digits.length);
631+ other.digits = newDigits;
632+ other.tempBuffer = null;
633+ return other;
634+ } catch (CloneNotSupportedException e) {
635+ throw new InternalError();
636+ }
637+ }
638+
639+ /**
640+ * Returns true if this DigitList represents Long.MIN_VALUE;
641+ * false, otherwise. This is required so that getLong() works.
642+ */
643+ private boolean isLongMIN_VALUE() {
644+ if (decimalAt != count || count != MAX_COUNT) {
645+ return false;
646+ }
647+
648+ for (int i = 0; i < count; ++i) {
649+ if (digits[i] != LONG_MIN_REP[i]) return false;
650+ }
651+
652+ return true;
653+ }
654+
655+ private static final int parseInt(char[] str, int offset, int strLen) {
656+ char c;
657+ boolean positive = true;
658+ if ((c = str[offset]) == '-') {
659+ positive = false;
660+ offset++;
661+ } else if (c == '+') {
662+ offset++;
663+ }
664+
665+ int value = 0;
666+ while (offset < strLen) {
667+ c = str[offset++];
668+ if (c >= '0' && c <= '9') {
669+ value = value * 10 + (c - '0');
670+ } else {
671+ break;
672+ }
673+ }
674+ return positive ? value : -value;
675+ }
676+
677+ // The digit part of -9223372036854775808L
678+ private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
679+
680+ public String toString() {
681+ if (isZero()) {
682+ return "0";
683+ }
684+ StringBuffer buf = getStringBuffer();
685+ buf.append("0.");
686+ buf.append(digits, 0, count);
687+ buf.append("x10^");
688+ buf.append(decimalAt);
689+ return buf.toString();
690+ }
691+
692+ private StringBuffer tempBuffer;
693+
694+ private StringBuffer getStringBuffer() {
695+ if (tempBuffer == null) {
696+ tempBuffer = new StringBuffer(MAX_COUNT);
697+ } else {
698+ tempBuffer.setLength(0);
699+ }
700+ return tempBuffer;
701+ }
702+
703+ private void extendDigits(int len) {
704+ if (len > digits.length) {
705+ digits = new char[len];
706+ }
707+ }
708+
709+ private final char[] getDataChars(int length) {
710+ if (data == null || data.length < length) {
711+ data = new char[length];
712+ }
713+ return data;
714+ }
715+}
java/pkg/java/text/DontCareFieldPosition$1.class+0−0

Binary file not shown.

java/pkg/java/text/DontCareFieldPosition.class+0−0

Binary file not shown.

java/pkg/java/text/DontCareFieldPosition.java+53−0
@@ -0,0 +1,53 @@
1+/*
2+ * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.text;
27+
28+/**
29+ * DontCareFieldPosition defines no-op FieldDelegate. Its
30+ * singleton is used for the format methods that don't take a
31+ * FieldPosition.
32+ */
33+class DontCareFieldPosition extends FieldPosition {
34+ // The singleton of DontCareFieldPosition.
35+ static final FieldPosition INSTANCE = new DontCareFieldPosition();
36+
37+ private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
38+ public void formatted(Format.Field attr, Object value, int start,
39+ int end, StringBuffer buffer) {
40+ }
41+ public void formatted(int fieldID, Format.Field attr, Object value,
42+ int start, int end, StringBuffer buffer) {
43+ }
44+ };
45+
46+ private DontCareFieldPosition() {
47+ super(0);
48+ }
49+
50+ Format.FieldDelegate getFieldDelegate() {
51+ return noDelegate;
52+ }
53+}
java/pkg/java/text/EntryPair.class+0−0

Binary file not shown.

java/pkg/java/text/EntryPair.java+60−0
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+/**
42+ * This is used for building contracting character tables. entryName
43+ * is the contracting character name and value is its collation
44+ * order.
45+ */
46+final class EntryPair
47+{
48+ public String entryName;
49+ public int value;
50+ public boolean fwd;
51+
52+ public EntryPair(String name, int value) {
53+ this(name, value, true);
54+ }
55+ public EntryPair(String name, int value, boolean fwd) {
56+ this.entryName = name;
57+ this.value = value;
58+ this.fwd = fwd;
59+ }
60+}
java/pkg/java/text/FieldPosition$1.class+0−0

Binary file not shown.

java/pkg/java/text/FieldPosition$Delegate.class+0−0

Binary file not shown.

java/pkg/java/text/FieldPosition.class+0−0

Binary file not shown.

java/pkg/java/text/FieldPosition.java+303−0
@@ -0,0 +1,303 @@
1+/*
2+ * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+/**
42+ * <code>FieldPosition</code> is a simple class used by <code>Format</code>
43+ * and its subclasses to identify fields in formatted output. Fields can
44+ * be identified in two ways:
45+ * <ul>
46+ * <li>By an integer constant, whose names typically end with
47+ * <code>_FIELD</code>. The constants are defined in the various
48+ * subclasses of <code>Format</code>.
49+ * <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
50+ * and its friends in <code>DateFormat</code> for an example.
51+ * </ul>
52+ * <p>
53+ * <code>FieldPosition</code> keeps track of the position of the
54+ * field within the formatted output with two indices: the index
55+ * of the first character of the field and the index of the last
56+ * character of the field.
57+ *
58+ * <p>
59+ * One version of the <code>format</code> method in the various
60+ * <code>Format</code> classes requires a <code>FieldPosition</code>
61+ * object as an argument. You use this <code>format</code> method
62+ * to perform partial formatting or to get information about the
63+ * formatted output (such as the position of a field).
64+ *
65+ * <p>
66+ * If you are interested in the positions of all attributes in the
67+ * formatted string use the <code>Format</code> method
68+ * <code>formatToCharacterIterator</code>.
69+ *
70+ * @author Mark Davis
71+ * @see java.text.Format
72+ */
73+public class FieldPosition {
74+
75+ /**
76+ * Input: Desired field to determine start and end offsets for.
77+ * The meaning depends on the subclass of Format.
78+ */
79+ int field = 0;
80+
81+ /**
82+ * Output: End offset of field in text.
83+ * If the field does not occur in the text, 0 is returned.
84+ */
85+ int endIndex = 0;
86+
87+ /**
88+ * Output: Start offset of field in text.
89+ * If the field does not occur in the text, 0 is returned.
90+ */
91+ int beginIndex = 0;
92+
93+ /**
94+ * Desired field this FieldPosition is for.
95+ */
96+ private Format.Field attribute;
97+
98+ /**
99+ * Creates a FieldPosition object for the given field. Fields are
100+ * identified by constants, whose names typically end with _FIELD,
101+ * in the various subclasses of Format.
102+ *
103+ * @see java.text.NumberFormat#INTEGER_FIELD
104+ * @see java.text.NumberFormat#FRACTION_FIELD
105+ * @see java.text.DateFormat#YEAR_FIELD
106+ * @see java.text.DateFormat#MONTH_FIELD
107+ */
108+ public FieldPosition(int field) {
109+ this.field = field;
110+ }
111+
112+ /**
113+ * Creates a FieldPosition object for the given field constant. Fields are
114+ * identified by constants defined in the various <code>Format</code>
115+ * subclasses. This is equivalent to calling
116+ * <code>new FieldPosition(attribute, -1)</code>.
117+ *
118+ * @param attribute Format.Field constant identifying a field
119+ * @since 1.4
120+ */
121+ public FieldPosition(Format.Field attribute) {
122+ this(attribute, -1);
123+ }
124+
125+ /**
126+ * Creates a <code>FieldPosition</code> object for the given field.
127+ * The field is identified by an attribute constant from one of the
128+ * <code>Field</code> subclasses as well as an integer field ID
129+ * defined by the <code>Format</code> subclasses. <code>Format</code>
130+ * subclasses that are aware of <code>Field</code> should give precedence
131+ * to <code>attribute</code> and ignore <code>fieldID</code> if
132+ * <code>attribute</code> is not null. However, older <code>Format</code>
133+ * subclasses may not be aware of <code>Field</code> and rely on
134+ * <code>fieldID</code>. If the field has no corresponding integer
135+ * constant, <code>fieldID</code> should be -1.
136+ *
137+ * @param attribute Format.Field constant identifying a field
138+ * @param fieldID integer constantce identifying a field
139+ * @since 1.4
140+ */
141+ public FieldPosition(Format.Field attribute, int fieldID) {
142+ this.attribute = attribute;
143+ this.field = fieldID;
144+ }
145+
146+ /**
147+ * Returns the field identifier as an attribute constant
148+ * from one of the <code>Field</code> subclasses. May return null if
149+ * the field is specified only by an integer field ID.
150+ *
151+ * @return Identifier for the field
152+ * @since 1.4
153+ */
154+ public Format.Field getFieldAttribute() {
155+ return attribute;
156+ }
157+
158+ /**
159+ * Retrieves the field identifier.
160+ */
161+ public int getField() {
162+ return field;
163+ }
164+
165+ /**
166+ * Retrieves the index of the first character in the requested field.
167+ */
168+ public int getBeginIndex() {
169+ return beginIndex;
170+ }
171+
172+ /**
173+ * Retrieves the index of the character following the last character in the
174+ * requested field.
175+ */
176+ public int getEndIndex() {
177+ return endIndex;
178+ }
179+
180+ /**
181+ * Sets the begin index. For use by subclasses of Format.
182+ * @since 1.2
183+ */
184+ public void setBeginIndex(int bi) {
185+ beginIndex = bi;
186+ }
187+
188+ /**
189+ * Sets the end index. For use by subclasses of Format.
190+ * @since 1.2
191+ */
192+ public void setEndIndex(int ei) {
193+ endIndex = ei;
194+ }
195+
196+ /**
197+ * Returns a <code>Format.FieldDelegate</code> instance that is associated
198+ * with the FieldPosition. When the delegate is notified of the same
199+ * field the FieldPosition is associated with, the begin/end will be
200+ * adjusted.
201+ */
202+ Format.FieldDelegate getFieldDelegate() {
203+ return new Delegate();
204+ }
205+
206+ /**
207+ * Overrides equals
208+ */
209+ public boolean equals(Object obj)
210+ {
211+ if (obj == null) return false;
212+ if (!(obj instanceof FieldPosition))
213+ return false;
214+ FieldPosition other = (FieldPosition) obj;
215+ if (attribute == null) {
216+ if (other.attribute != null) {
217+ return false;
218+ }
219+ }
220+ else if (!attribute.equals(other.attribute)) {
221+ return false;
222+ }
223+ return (beginIndex == other.beginIndex
224+ && endIndex == other.endIndex
225+ && field == other.field);
226+ }
227+
228+ /**
229+ * Returns a hash code for this FieldPosition.
230+ * @return a hash code value for this object
231+ */
232+ public int hashCode() {
233+ return (field << 24) | (beginIndex << 16) | endIndex;
234+ }
235+
236+ /**
237+ * Return a string representation of this FieldPosition.
238+ * @return a string representation of this object
239+ */
240+ public String toString() {
241+ return getClass().getName() +
242+ "[field=" + field + ",attribute=" + attribute +
243+ ",beginIndex=" + beginIndex +
244+ ",endIndex=" + endIndex + ']';
245+ }
246+
247+
248+ /**
249+ * Return true if the receiver wants a <code>Format.Field</code> value and
250+ * <code>attribute</code> is equal to it.
251+ */
252+ private boolean matchesField(Format.Field attribute) {
253+ if (this.attribute != null) {
254+ return this.attribute.equals(attribute);
255+ }
256+ return false;
257+ }
258+
259+ /**
260+ * Return true if the receiver wants a <code>Format.Field</code> value and
261+ * <code>attribute</code> is equal to it, or true if the receiver
262+ * represents an inteter constant and <code>field</code> equals it.
263+ */
264+ private boolean matchesField(Format.Field attribute, int field) {
265+ if (this.attribute != null) {
266+ return this.attribute.equals(attribute);
267+ }
268+ return (field == this.field);
269+ }
270+
271+
272+ /**
273+ * An implementation of FieldDelegate that will adjust the begin/end
274+ * of the FieldPosition if the arguments match the field of
275+ * the FieldPosition.
276+ */
277+ private class Delegate implements Format.FieldDelegate {
278+ /**
279+ * Indicates whether the field has been encountered before. If this
280+ * is true, and <code>formatted</code> is invoked, the begin/end
281+ * are not updated.
282+ */
283+ private boolean encounteredField;
284+
285+ public void formatted(Format.Field attr, Object value, int start,
286+ int end, StringBuffer buffer) {
287+ if (!encounteredField && matchesField(attr)) {
288+ setBeginIndex(start);
289+ setEndIndex(end);
290+ encounteredField = (start != end);
291+ }
292+ }
293+
294+ public void formatted(int fieldID, Format.Field attr, Object value,
295+ int start, int end, StringBuffer buffer) {
296+ if (!encounteredField && matchesField(attr, fieldID)) {
297+ setBeginIndex(start);
298+ setEndIndex(end);
299+ encounteredField = (start != end);
300+ }
301+ }
302+ }
303+}
java/pkg/java/text/Format$Field.class+0−0

Binary file not shown.

java/pkg/java/text/Format$FieldDelegate.class+0−0

Binary file not shown.

java/pkg/java/text/Format.class+0−0

Binary file not shown.

java/pkg/java/text/Format.java+406−0
@@ -0,0 +1,406 @@
1+/*
2+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.Serializable;
42+
43+/**
44+ * <code>Format</code> is an abstract base class for formatting locale-sensitive
45+ * information such as dates, messages, and numbers.
46+ *
47+ * <p>
48+ * <code>Format</code> defines the programming interface for formatting
49+ * locale-sensitive objects into <code>String</code>s (the
50+ * <code>format</code> method) and for parsing <code>String</code>s back
51+ * into objects (the <code>parseObject</code> method).
52+ *
53+ * <p>
54+ * Generally, a format's <code>parseObject</code> method must be able to parse
55+ * any string formatted by its <code>format</code> method. However, there may
56+ * be exceptional cases where this is not possible. For example, a
57+ * <code>format</code> method might create two adjacent integer numbers with
58+ * no separator in between, and in this case the <code>parseObject</code> could
59+ * not tell which digits belong to which number.
60+ *
61+ * <h4>Subclassing</h4>
62+ *
63+ * <p>
64+ * The Java Platform provides three specialized subclasses of <code>Format</code>--
65+ * <code>DateFormat</code>, <code>MessageFormat</code>, and
66+ * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
67+ * respectively.
68+ * <p>
69+ * Concrete subclasses must implement three methods:
70+ * <ol>
71+ * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
72+ * <li> <code>formatToCharacterIterator(Object obj)</code>
73+ * <li> <code>parseObject(String source, ParsePosition pos)</code>
74+ * </ol>
75+ * These general methods allow polymorphic parsing and formatting of objects
76+ * and are used, for example, by <code>MessageFormat</code>.
77+ * Subclasses often also provide additional <code>format</code> methods for
78+ * specific input types as well as <code>parse</code> methods for specific
79+ * result types. Any <code>parse</code> method that does not take a
80+ * <code>ParsePosition</code> argument should throw <code>ParseException</code>
81+ * when no text in the required format is at the beginning of the input text.
82+ *
83+ * <p>
84+ * Most subclasses will also implement the following factory methods:
85+ * <ol>
86+ * <li>
87+ * <code>getInstance</code> for getting a useful format object appropriate
88+ * for the current locale
89+ * <li>
90+ * <code>getInstance(Locale)</code> for getting a useful format
91+ * object appropriate for the specified locale
92+ * </ol>
93+ * In addition, some subclasses may also implement other
94+ * <code>getXxxxInstance</code> methods for more specialized control. For
95+ * example, the <code>NumberFormat</code> class provides
96+ * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
97+ * methods for getting specialized number formatters.
98+ *
99+ * <p>
100+ * Subclasses of <code>Format</code> that allow programmers to create objects
101+ * for locales (with <code>getInstance(Locale)</code> for example)
102+ * must also implement the following class method:
103+ * <blockquote>
104+ * <pre>
105+ * public static Locale[] getAvailableLocales()
106+ * </pre>
107+ * </blockquote>
108+ *
109+ * <p>
110+ * And finally subclasses may define a set of constants to identify the various
111+ * fields in the formatted output. These constants are used to create a FieldPosition
112+ * object which identifies what information is contained in the field and its
113+ * position in the formatted result. These constants should be named
114+ * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
115+ * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
116+ * friends in {@link DateFormat}.
117+ *
118+ * <h4><a name="synchronization">Synchronization</a></h4>
119+ *
120+ * <p>
121+ * Formats are generally not synchronized.
122+ * It is recommended to create separate format instances for each thread.
123+ * If multiple threads access a format concurrently, it must be synchronized
124+ * externally.
125+ *
126+ * @see java.text.ParsePosition
127+ * @see java.text.FieldPosition
128+ * @see java.text.NumberFormat
129+ * @see java.text.DateFormat
130+ * @see java.text.MessageFormat
131+ * @author Mark Davis
132+ */
133+public abstract class Format implements Serializable, Cloneable {
134+
135+ private static final long serialVersionUID = -299282585814624189L;
136+
137+ /**
138+ * Sole constructor. (For invocation by subclass constructors, typically
139+ * implicit.)
140+ */
141+ protected Format() {
142+ }
143+
144+ /**
145+ * Formats an object to produce a string. This is equivalent to
146+ * <blockquote>
147+ * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
148+ * new StringBuffer(), new FieldPosition(0)).toString();</code>
149+ * </blockquote>
150+ *
151+ * @param obj The object to format
152+ * @return Formatted string.
153+ * @exception IllegalArgumentException if the Format cannot format the given
154+ * object
155+ */
156+ public final String format (Object obj) {
157+ return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
158+ }
159+
160+ /**
161+ * Formats an object and appends the resulting text to a given string
162+ * buffer.
163+ * If the <code>pos</code> argument identifies a field used by the format,
164+ * then its indices are set to the beginning and end of the first such
165+ * field encountered.
166+ *
167+ * @param obj The object to format
168+ * @param toAppendTo where the text is to be appended
169+ * @param pos A <code>FieldPosition</code> identifying a field
170+ * in the formatted text
171+ * @return the string buffer passed in as <code>toAppendTo</code>,
172+ * with formatted text appended
173+ * @exception NullPointerException if <code>toAppendTo</code> or
174+ * <code>pos</code> is null
175+ * @exception IllegalArgumentException if the Format cannot format the given
176+ * object
177+ */
178+ public abstract StringBuffer format(Object obj,
179+ StringBuffer toAppendTo,
180+ FieldPosition pos);
181+
182+ /**
183+ * Formats an Object producing an <code>AttributedCharacterIterator</code>.
184+ * You can use the returned <code>AttributedCharacterIterator</code>
185+ * to build the resulting String, as well as to determine information
186+ * about the resulting String.
187+ * <p>
188+ * Each attribute key of the AttributedCharacterIterator will be of type
189+ * <code>Field</code>. It is up to each <code>Format</code> implementation
190+ * to define what the legal values are for each attribute in the
191+ * <code>AttributedCharacterIterator</code>, but typically the attribute
192+ * key is also used as the attribute value.
193+ * <p>The default implementation creates an
194+ * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
195+ * that support fields should override this and create an
196+ * <code>AttributedCharacterIterator</code> with meaningful attributes.
197+ *
198+ * @exception NullPointerException if obj is null.
199+ * @exception IllegalArgumentException when the Format cannot format the
200+ * given object.
201+ * @param obj The object to format
202+ * @return AttributedCharacterIterator describing the formatted value.
203+ * @since 1.4
204+ */
205+ public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
206+ return createAttributedCharacterIterator(format(obj));
207+ }
208+
209+ /**
210+ * Parses text from a string to produce an object.
211+ * <p>
212+ * The method attempts to parse text starting at the index given by
213+ * <code>pos</code>.
214+ * If parsing succeeds, then the index of <code>pos</code> is updated
215+ * to the index after the last character used (parsing does not necessarily
216+ * use all characters up to the end of the string), and the parsed
217+ * object is returned. The updated <code>pos</code> can be used to
218+ * indicate the starting point for the next call to this method.
219+ * If an error occurs, then the index of <code>pos</code> is not
220+ * changed, the error index of <code>pos</code> is set to the index of
221+ * the character where the error occurred, and null is returned.
222+ *
223+ * @param source A <code>String</code>, part of which should be parsed.
224+ * @param pos A <code>ParsePosition</code> object with index and error
225+ * index information as described above.
226+ * @return An <code>Object</code> parsed from the string. In case of
227+ * error, returns null.
228+ * @exception NullPointerException if <code>pos</code> is null.
229+ */
230+ public abstract Object parseObject (String source, ParsePosition pos);
231+
232+ /**
233+ * Parses text from the beginning of the given string to produce an object.
234+ * The method may not use the entire text of the given string.
235+ *
236+ * @param source A <code>String</code> whose beginning should be parsed.
237+ * @return An <code>Object</code> parsed from the string.
238+ * @exception ParseException if the beginning of the specified string
239+ * cannot be parsed.
240+ */
241+ public Object parseObject(String source) throws ParseException {
242+ ParsePosition pos = new ParsePosition(0);
243+ Object result = parseObject(source, pos);
244+ if (pos.index == 0) {
245+ throw new ParseException("Format.parseObject(String) failed",
246+ pos.errorIndex);
247+ }
248+ return result;
249+ }
250+
251+ /**
252+ * Creates and returns a copy of this object.
253+ *
254+ * @return a clone of this instance.
255+ */
256+ public Object clone() {
257+ try {
258+ return super.clone();
259+ } catch (CloneNotSupportedException e) {
260+ // will never happen
261+ return null;
262+ }
263+ }
264+
265+ //
266+ // Convenience methods for creating AttributedCharacterIterators from
267+ // different parameters.
268+ //
269+
270+ /**
271+ * Creates an <code>AttributedCharacterIterator</code> for the String
272+ * <code>s</code>.
273+ *
274+ * @param s String to create AttributedCharacterIterator from
275+ * @return AttributedCharacterIterator wrapping s
276+ */
277+ AttributedCharacterIterator createAttributedCharacterIterator(String s) {
278+ AttributedString as = new AttributedString(s);
279+
280+ return as.getIterator();
281+ }
282+
283+ /**
284+ * Creates an <code>AttributedCharacterIterator</code> containg the
285+ * concatenated contents of the passed in
286+ * <code>AttributedCharacterIterator</code>s.
287+ *
288+ * @param iterators AttributedCharacterIterators used to create resulting
289+ * AttributedCharacterIterators
290+ * @return AttributedCharacterIterator wrapping passed in
291+ * AttributedCharacterIterators
292+ */
293+ AttributedCharacterIterator createAttributedCharacterIterator(
294+ AttributedCharacterIterator[] iterators) {
295+ AttributedString as = new AttributedString(iterators);
296+
297+ return as.getIterator();
298+ }
299+
300+ /**
301+ * Returns an AttributedCharacterIterator with the String
302+ * <code>string</code> and additional key/value pair <code>key</code>,
303+ * <code>value</code>.
304+ *
305+ * @param string String to create AttributedCharacterIterator from
306+ * @param key Key for AttributedCharacterIterator
307+ * @param value Value associated with key in AttributedCharacterIterator
308+ * @return AttributedCharacterIterator wrapping args
309+ */
310+ AttributedCharacterIterator createAttributedCharacterIterator(
311+ String string, AttributedCharacterIterator.Attribute key,
312+ Object value) {
313+ AttributedString as = new AttributedString(string);
314+
315+ as.addAttribute(key, value);
316+ return as.getIterator();
317+ }
318+
319+ /**
320+ * Creates an AttributedCharacterIterator with the contents of
321+ * <code>iterator</code> and the additional attribute <code>key</code>
322+ * <code>value</code>.
323+ *
324+ * @param iterator Initial AttributedCharacterIterator to add arg to
325+ * @param key Key for AttributedCharacterIterator
326+ * @param value Value associated with key in AttributedCharacterIterator
327+ * @return AttributedCharacterIterator wrapping args
328+ */
329+ AttributedCharacterIterator createAttributedCharacterIterator(
330+ AttributedCharacterIterator iterator,
331+ AttributedCharacterIterator.Attribute key, Object value) {
332+ AttributedString as = new AttributedString(iterator);
333+
334+ as.addAttribute(key, value);
335+ return as.getIterator();
336+ }
337+
338+
339+ /**
340+ * Defines constants that are used as attribute keys in the
341+ * <code>AttributedCharacterIterator</code> returned
342+ * from <code>Format.formatToCharacterIterator</code> and as
343+ * field identifiers in <code>FieldPosition</code>.
344+ *
345+ * @since 1.4
346+ */
347+ public static class Field extends AttributedCharacterIterator.Attribute {
348+
349+ // Proclaim serial compatibility with 1.4 FCS
350+ private static final long serialVersionUID = 276966692217360283L;
351+
352+ /**
353+ * Creates a Field with the specified name.
354+ *
355+ * @param name Name of the attribute
356+ */
357+ protected Field(String name) {
358+ super(name);
359+ }
360+ }
361+
362+
363+ /**
364+ * FieldDelegate is notified by the various <code>Format</code>
365+ * implementations as they are formatting the Objects. This allows for
366+ * storage of the individual sections of the formatted String for
367+ * later use, such as in a <code>FieldPosition</code> or for an
368+ * <code>AttributedCharacterIterator</code>.
369+ * <p>
370+ * Delegates should NOT assume that the <code>Format</code> will notify
371+ * the delegate of fields in any particular order.
372+ *
373+ * @see FieldPosition.Delegate
374+ * @see CharacterIteratorFieldDelegate
375+ */
376+ interface FieldDelegate {
377+ /**
378+ * Notified when a particular region of the String is formatted. This
379+ * method will be invoked if there is no corresponding integer field id
380+ * matching <code>attr</code>.
381+ *
382+ * @param attr Identifies the field matched
383+ * @param value Value associated with the field
384+ * @param start Beginning location of the field, will be >= 0
385+ * @param end End of the field, will be >= start and <= buffer.length()
386+ * @param buffer Contains current formatted value, receiver should
387+ * NOT modify it.
388+ */
389+ public void formatted(Format.Field attr, Object value, int start,
390+ int end, StringBuffer buffer);
391+
392+ /**
393+ * Notified when a particular region of the String is formatted.
394+ *
395+ * @param fieldID Identifies the field by integer
396+ * @param attr Identifies the field matched
397+ * @param value Value associated with the field
398+ * @param start Beginning location of the field, will be >= 0
399+ * @param end End of the field, will be >= start and <= buffer.length()
400+ * @param buffer Contains current formatted value, receiver should
401+ * NOT modify it.
402+ */
403+ public void formatted(int fieldID, Format.Field attr, Object value,
404+ int start, int end, StringBuffer buffer);
405+ }
406+}
java/pkg/java/text/MergeCollation.class+0−0

Binary file not shown.

java/pkg/java/text/MergeCollation.java+342−0
@@ -0,0 +1,342 @@
1+/*
2+ * Copyright (c) 1996, 1999, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.util.ArrayList;
42+
43+/**
44+ * Utility class for normalizing and merging patterns for collation.
45+ * Patterns are strings of the form <entry>*, where <entry> has the
46+ * form:
47+ * <pattern> := <entry>*
48+ * <entry> := <separator><chars>{"/"<extension>}
49+ * <separator> := "=", ",", ";", "<", "&"
50+ * <chars>, and <extension> are both arbitrary strings.
51+ * unquoted whitespaces are ignored.
52+ * 'xxx' can be used to quote characters
53+ * One difference from Collator is that & is used to reset to a current
54+ * point. Or, in other words, it introduces a new sequence which is to
55+ * be added to the old.
56+ * That is: "a < b < c < d" is the same as "a < b & b < c & c < d" OR
57+ * "a < b < d & b < c"
58+ * XXX: make '' be a single quote.
59+ * @see PatternEntry
60+ * @author Mark Davis, Helena Shih
61+ */
62+
63+final class MergeCollation {
64+
65+ /**
66+ * Creates from a pattern
67+ * @exception ParseException If the input pattern is incorrect.
68+ */
69+ public MergeCollation(String pattern) throws ParseException
70+ {
71+ for (int i = 0; i < statusArray.length; i++)
72+ statusArray[i] = 0;
73+ setPattern(pattern);
74+ }
75+
76+ /**
77+ * recovers current pattern
78+ */
79+ public String getPattern() {
80+ return getPattern(true);
81+ }
82+
83+ /**
84+ * recovers current pattern.
85+ * @param withWhiteSpace puts spacing around the entries, and \n
86+ * before & and <
87+ */
88+ public String getPattern(boolean withWhiteSpace) {
89+ StringBuffer result = new StringBuffer();
90+ PatternEntry tmp = null;
91+ ArrayList extList = null;
92+ int i;
93+ for (i = 0; i < patterns.size(); ++i) {
94+ PatternEntry entry = (PatternEntry) patterns.get(i);
95+ if (entry.extension.length() != 0) {
96+ if (extList == null)
97+ extList = new ArrayList();
98+ extList.add(entry);
99+ } else {
100+ if (extList != null) {
101+ PatternEntry last = findLastWithNoExtension(i-1);
102+ for (int j = extList.size() - 1; j >= 0 ; j--) {
103+ tmp = (PatternEntry)(extList.get(j));
104+ tmp.addToBuffer(result, false, withWhiteSpace, last);
105+ }
106+ extList = null;
107+ }
108+ entry.addToBuffer(result, false, withWhiteSpace, null);
109+ }
110+ }
111+ if (extList != null) {
112+ PatternEntry last = findLastWithNoExtension(i-1);
113+ for (int j = extList.size() - 1; j >= 0 ; j--) {
114+ tmp = (PatternEntry)(extList.get(j));
115+ tmp.addToBuffer(result, false, withWhiteSpace, last);
116+ }
117+ extList = null;
118+ }
119+ return result.toString();
120+ }
121+
122+ private final PatternEntry findLastWithNoExtension(int i) {
123+ for (--i;i >= 0; --i) {
124+ PatternEntry entry = (PatternEntry) patterns.get(i);
125+ if (entry.extension.length() == 0) {
126+ return entry;
127+ }
128+ }
129+ return null;
130+ }
131+
132+ /**
133+ * emits the pattern for collation builder.
134+ * @return emits the string in the format understable to the collation
135+ * builder.
136+ */
137+ public String emitPattern() {
138+ return emitPattern(true);
139+ }
140+
141+ /**
142+ * emits the pattern for collation builder.
143+ * @param withWhiteSpace puts spacing around the entries, and \n
144+ * before & and <
145+ * @return emits the string in the format understable to the collation
146+ * builder.
147+ */
148+ public String emitPattern(boolean withWhiteSpace) {
149+ StringBuffer result = new StringBuffer();
150+ for (int i = 0; i < patterns.size(); ++i)
151+ {
152+ PatternEntry entry = (PatternEntry) patterns.get(i);
153+ if (entry != null) {
154+ entry.addToBuffer(result, true, withWhiteSpace, null);
155+ }
156+ }
157+ return result.toString();
158+ }
159+
160+ /**
161+ * sets the pattern.
162+ */
163+ public void setPattern(String pattern) throws ParseException
164+ {
165+ patterns.clear();
166+ addPattern(pattern);
167+ }
168+
169+ /**
170+ * adds a pattern to the current one.
171+ * @param pattern the new pattern to be added
172+ */
173+ public void addPattern(String pattern) throws ParseException
174+ {
175+ if (pattern == null)
176+ return;
177+
178+ PatternEntry.Parser parser = new PatternEntry.Parser(pattern);
179+
180+ PatternEntry entry = parser.next();
181+ while (entry != null) {
182+ fixEntry(entry);
183+ entry = parser.next();
184+ }
185+ }
186+
187+ /**
188+ * gets count of separate entries
189+ * @return the size of pattern entries
190+ */
191+ public int getCount() {
192+ return patterns.size();
193+ }
194+
195+ /**
196+ * gets count of separate entries
197+ * @param index the offset of the desired pattern entry
198+ * @return the requested pattern entry
199+ */
200+ public PatternEntry getItemAt(int index) {
201+ return (PatternEntry) patterns.get(index);
202+ }
203+
204+ //============================================================
205+ // privates
206+ //============================================================
207+ ArrayList patterns = new ArrayList(); // a list of PatternEntries
208+
209+ private transient PatternEntry saveEntry = null;
210+ private transient PatternEntry lastEntry = null;
211+
212+ // This is really used as a local variable inside fixEntry, but we cache
213+ // it here to avoid newing it up every time the method is called.
214+ private transient StringBuffer excess = new StringBuffer();
215+
216+ //
217+ // When building a MergeCollation, we need to do lots of searches to see
218+ // whether a given entry is already in the table. Since we're using an
219+ // array, this would make the algorithm O(N*N). To speed things up, we
220+ // use this bit array to remember whether the array contains any entries
221+ // starting with each Unicode character. If not, we can avoid the search.
222+ // Using BitSet would make this easier, but it's significantly slower.
223+ //
224+ private transient byte[] statusArray = new byte[8192];
225+ private final byte BITARRAYMASK = (byte)0x1;
226+ private final int BYTEPOWER = 3;
227+ private final int BYTEMASK = (1 << BYTEPOWER) - 1;
228+
229+ /*
230+ If the strength is RESET, then just change the lastEntry to
231+ be the current. (If the current is not in patterns, signal an error).
232+ If not, then remove the current entry, and add it after lastEntry
233+ (which is usually at the end).
234+ */
235+ private final void fixEntry(PatternEntry newEntry) throws ParseException
236+ {
237+ // check to see whether the new entry has the same characters as the previous
238+ // entry did (this can happen when a pattern declaring a difference between two
239+ // strings that are canonically equivalent is normalized). If so, and the strength
240+ // is anything other than IDENTICAL or RESET, throw an exception (you can't
241+ // declare a string to be unequal to itself). --rtg 5/24/99
242+ if (lastEntry != null && newEntry.chars.equals(lastEntry.chars)
243+ && newEntry.extension.equals(lastEntry.extension)) {
244+ if (newEntry.strength != Collator.IDENTICAL
245+ && newEntry.strength != PatternEntry.RESET) {
246+ throw new ParseException("The entries " + lastEntry + " and "
247+ + newEntry + " are adjacent in the rules, but have conflicting "
248+ + "strengths: A character can't be unequal to itself.", -1);
249+ } else {
250+ // otherwise, just skip this entry and behave as though you never saw it
251+ return;
252+ }
253+ }
254+
255+ boolean changeLastEntry = true;
256+ if (newEntry.strength != PatternEntry.RESET) {
257+ int oldIndex = -1;
258+
259+ if ((newEntry.chars.length() == 1)) {
260+
261+ char c = newEntry.chars.charAt(0);
262+ int statusIndex = c >> BYTEPOWER;
263+ byte bitClump = statusArray[statusIndex];
264+ byte setBit = (byte)(BITARRAYMASK << (c & BYTEMASK));
265+
266+ if (bitClump != 0 && (bitClump & setBit) != 0) {
267+ oldIndex = patterns.lastIndexOf(newEntry);
268+ } else {
269+ // We're going to add an element that starts with this
270+ // character, so go ahead and set its bit.
271+ statusArray[statusIndex] = (byte)(bitClump | setBit);
272+ }
273+ } else {
274+ oldIndex = patterns.lastIndexOf(newEntry);
275+ }
276+ if (oldIndex != -1) {
277+ patterns.remove(oldIndex);
278+ }
279+
280+ excess.setLength(0);
281+ int lastIndex = findLastEntry(lastEntry, excess);
282+
283+ if (excess.length() != 0) {
284+ newEntry.extension = excess + newEntry.extension;
285+ if (lastIndex != patterns.size()) {
286+ lastEntry = saveEntry;
287+ changeLastEntry = false;
288+ }
289+ }
290+ if (lastIndex == patterns.size()) {
291+ patterns.add(newEntry);
292+ saveEntry = newEntry;
293+ } else {
294+ patterns.add(lastIndex, newEntry);
295+ }
296+ }
297+ if (changeLastEntry) {
298+ lastEntry = newEntry;
299+ }
300+ }
301+
302+ private final int findLastEntry(PatternEntry entry,
303+ StringBuffer excessChars) throws ParseException
304+ {
305+ if (entry == null)
306+ return 0;
307+
308+ if (entry.strength != PatternEntry.RESET) {
309+ // Search backwards for string that contains this one;
310+ // most likely entry is last one
311+
312+ int oldIndex = -1;
313+ if ((entry.chars.length() == 1)) {
314+ int index = entry.chars.charAt(0) >> BYTEPOWER;
315+ if ((statusArray[index] &
316+ (BITARRAYMASK << (entry.chars.charAt(0) & BYTEMASK))) != 0) {
317+ oldIndex = patterns.lastIndexOf(entry);
318+ }
319+ } else {
320+ oldIndex = patterns.lastIndexOf(entry);
321+ }
322+ if ((oldIndex == -1))
323+ throw new ParseException("couldn't find last entry: "
324+ + entry, oldIndex);
325+ return oldIndex + 1;
326+ } else {
327+ int i;
328+ for (i = patterns.size() - 1; i >= 0; --i) {
329+ PatternEntry e = (PatternEntry) patterns.get(i);
330+ if (e.chars.regionMatches(0,entry.chars,0,
331+ e.chars.length())) {
332+ excessChars.append(entry.chars.substring(e.chars.length(),
333+ entry.chars.length()));
334+ break;
335+ }
336+ }
337+ if (i == -1)
338+ throw new ParseException("couldn't find: " + entry, i);
339+ return i + 1;
340+ }
341+ }
342+}
java/pkg/java/text/MessageFormat$Field.class+0−0

Binary file not shown.

java/pkg/java/text/MessageFormat.class+0−0

Binary file not shown.

java/pkg/java/text/MessageFormat.java+1594−0
@@ -0,0 +1,1594 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.InvalidObjectException;
42+import java.io.IOException;
43+import java.io.ObjectInputStream;
44+import java.text.DecimalFormat;
45+import java.util.ArrayList;
46+import java.util.Arrays;
47+import java.util.Date;
48+import java.util.List;
49+import java.util.Locale;
50+
51+
52+/**
53+ * <code>MessageFormat</code> provides a means to produce concatenated
54+ * messages in a language-neutral way. Use this to construct messages
55+ * displayed for end users.
56+ *
57+ * <p>
58+ * <code>MessageFormat</code> takes a set of objects, formats them, then
59+ * inserts the formatted strings into the pattern at the appropriate places.
60+ *
61+ * <p>
62+ * <strong>Note:</strong>
63+ * <code>MessageFormat</code> differs from the other <code>Format</code>
64+ * classes in that you create a <code>MessageFormat</code> object with one
65+ * of its constructors (not with a <code>getInstance</code> style factory
66+ * method). The factory methods aren't necessary because <code>MessageFormat</code>
67+ * itself doesn't implement locale specific behavior. Any locale specific
68+ * behavior is defined by the pattern that you provide as well as the
69+ * subformats used for inserted arguments.
70+ *
71+ * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
72+ *
73+ * <code>MessageFormat</code> uses patterns of the following form:
74+ * <blockquote><pre>
75+ * <i>MessageFormatPattern:</i>
76+ * <i>String</i>
77+ * <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
78+ *
79+ * <i>FormatElement:</i>
80+ * { <i>ArgumentIndex</i> }
81+ * { <i>ArgumentIndex</i> , <i>FormatType</i> }
82+ * { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
83+ *
84+ * <i>FormatType: one of </i>
85+ * number date time choice
86+ *
87+ * <i>FormatStyle:</i>
88+ * short
89+ * medium
90+ * long
91+ * full
92+ * integer
93+ * currency
94+ * percent
95+ * <i>SubformatPattern</i>
96+ * </pre></blockquote>
97+ *
98+ * <p>Within a <i>String</i>, a pair of single quotes can be used to
99+ * quote any arbitrary characters except single quotes. For example,
100+ * pattern string <code>"'{0}'"</code> represents string
101+ * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
102+ * must be represented by doubled single quotes {@code ''} throughout a
103+ * <i>String</i>. For example, pattern string <code>"'{''}'"</code> is
104+ * interpreted as a sequence of <code>'{</code> (start of quoting and a
105+ * left curly brace), <code>''</code> (a single quote), and
106+ * <code>}'</code> (a right curly brace and end of quoting),
107+ * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
108+ * right curly braces): representing string <code>"{'}"</code>,
109+ * <em>not</em> <code>"{}"</code>.
110+ *
111+ * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
112+ * subformat, and subformat-dependent pattern rules apply. For example,
113+ * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
114+ * (<i>SubformatPattern</i> with underline) will produce a number format
115+ * with the pound-sign quoted, with a result such as: {@code
116+ * "$#31,45"}. Refer to each {@code Format} subclass documentation for
117+ * details.
118+ *
119+ * <p>Any unmatched quote is treated as closed at the end of the given
120+ * pattern. For example, pattern string {@code "'{0}"} is treated as
121+ * pattern {@code "'{0}'"}.
122+ *
123+ * <p>Any curly braces within an unquoted pattern must be balanced. For
124+ * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
125+ * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
126+ * and <code>"''{''"</code> are not.
127+ *
128+ * <p>
129+ * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
130+ * format patterns unfortunately have shown to be somewhat confusing.
131+ * In particular, it isn't always obvious to localizers whether single
132+ * quotes need to be doubled or not. Make sure to inform localizers about
133+ * the rules, and tell them (for example, by using comments in resource
134+ * bundle source files) which strings will be processed by {@code MessageFormat}.
135+ * Note that localizers may need to use single quotes in translated
136+ * strings where the original version doesn't have them.
137+ * </dl>
138+ * <p>
139+ * The <i>ArgumentIndex</i> value is a non-negative integer written
140+ * using the digits {@code '0'} through {@code '9'}, and represents an index into the
141+ * {@code arguments} array passed to the {@code format} methods
142+ * or the result array returned by the {@code parse} methods.
143+ * <p>
144+ * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
145+ * a {@code Format} instance for the format element. The following
146+ * table shows how the values map to {@code Format} instances. Combinations not
147+ * shown in the table are illegal. A <i>SubformatPattern</i> must
148+ * be a valid pattern string for the {@code Format} subclass used.
149+ * <p>
150+ * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
151+ * <tr>
152+ * <th id="ft" class="TableHeadingColor">FormatType
153+ * <th id="fs" class="TableHeadingColor">FormatStyle
154+ * <th id="sc" class="TableHeadingColor">Subformat Created
155+ * <tr>
156+ * <td headers="ft"><i>(none)</i>
157+ * <td headers="fs"><i>(none)</i>
158+ * <td headers="sc"><code>null</code>
159+ * <tr>
160+ * <td headers="ft" rowspan=5><code>number</code>
161+ * <td headers="fs"><i>(none)</i>
162+ * <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
163+ * <tr>
164+ * <td headers="fs"><code>integer</code>
165+ * <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
166+ * <tr>
167+ * <td headers="fs"><code>currency</code>
168+ * <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
169+ * <tr>
170+ * <td headers="fs"><code>percent</code>
171+ * <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
172+ * <tr>
173+ * <td headers="fs"><i>SubformatPattern</i>
174+ * <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
175+ * <tr>
176+ * <td headers="ft" rowspan=6><code>date</code>
177+ * <td headers="fs"><i>(none)</i>
178+ * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
179+ * <tr>
180+ * <td headers="fs"><code>short</code>
181+ * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
182+ * <tr>
183+ * <td headers="fs"><code>medium</code>
184+ * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
185+ * <tr>
186+ * <td headers="fs"><code>long</code>
187+ * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
188+ * <tr>
189+ * <td headers="fs"><code>full</code>
190+ * <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
191+ * <tr>
192+ * <td headers="fs"><i>SubformatPattern</i>
193+ * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
194+ * <tr>
195+ * <td headers="ft" rowspan=6><code>time</code>
196+ * <td headers="fs"><i>(none)</i>
197+ * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
198+ * <tr>
199+ * <td headers="fs"><code>short</code>
200+ * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
201+ * <tr>
202+ * <td headers="fs"><code>medium</code>
203+ * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
204+ * <tr>
205+ * <td headers="fs"><code>long</code>
206+ * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
207+ * <tr>
208+ * <td headers="fs"><code>full</code>
209+ * <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
210+ * <tr>
211+ * <td headers="fs"><i>SubformatPattern</i>
212+ * <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
213+ * <tr>
214+ * <td headers="ft"><code>choice</code>
215+ * <td headers="fs"><i>SubformatPattern</i>
216+ * <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
217+ * </table>
218+ * <p>
219+ *
220+ * <h4>Usage Information</h4>
221+ *
222+ * <p>
223+ * Here are some examples of usage.
224+ * In real internationalized programs, the message format pattern and other
225+ * static strings will, of course, be obtained from resource bundles.
226+ * Other parameters will be dynamically determined at runtime.
227+ * <p>
228+ * The first example uses the static method <code>MessageFormat.format</code>,
229+ * which internally creates a <code>MessageFormat</code> for one-time use:
230+ * <blockquote><pre>
231+ * int planet = 7;
232+ * String event = "a disturbance in the Force";
233+ *
234+ * String result = MessageFormat.format(
235+ * "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
236+ * planet, new Date(), event);
237+ * </pre></blockquote>
238+ * The output is:
239+ * <blockquote><pre>
240+ * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
241+ * </pre></blockquote>
242+ *
243+ * <p>
244+ * The following example creates a <code>MessageFormat</code> instance that
245+ * can be used repeatedly:
246+ * <blockquote><pre>
247+ * int fileCount = 1273;
248+ * String diskName = "MyDisk";
249+ * Object[] testArgs = {new Long(fileCount), diskName};
250+ *
251+ * MessageFormat form = new MessageFormat(
252+ * "The disk \"{1}\" contains {0} file(s).");
253+ *
254+ * System.out.println(form.format(testArgs));
255+ * </pre></blockquote>
256+ * The output with different values for <code>fileCount</code>:
257+ * <blockquote><pre>
258+ * The disk "MyDisk" contains 0 file(s).
259+ * The disk "MyDisk" contains 1 file(s).
260+ * The disk "MyDisk" contains 1,273 file(s).
261+ * </pre></blockquote>
262+ *
263+ * <p>
264+ * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
265+ * to produce correct forms for singular and plural:
266+ * <blockquote><pre>
267+ * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
268+ * double[] filelimits = {0,1,2};
269+ * String[] filepart = {"no files","one file","{0,number} files"};
270+ * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
271+ * form.setFormatByArgumentIndex(0, fileform);
272+ *
273+ * int fileCount = 1273;
274+ * String diskName = "MyDisk";
275+ * Object[] testArgs = {new Long(fileCount), diskName};
276+ *
277+ * System.out.println(form.format(testArgs));
278+ * </pre></blockquote>
279+ * The output with different values for <code>fileCount</code>:
280+ * <blockquote><pre>
281+ * The disk "MyDisk" contains no files.
282+ * The disk "MyDisk" contains one file.
283+ * The disk "MyDisk" contains 1,273 files.
284+ * </pre></blockquote>
285+ *
286+ * <p>
287+ * You can create the <code>ChoiceFormat</code> programmatically, as in the
288+ * above example, or by using a pattern. See {@link ChoiceFormat}
289+ * for more information.
290+ * <blockquote><pre>
291+ * form.applyPattern(
292+ * "There {0,choice,0#are no files|1#is one file|1&lt;are {0,number,integer} files}.");
293+ * </pre></blockquote>
294+ *
295+ * <p>
296+ * <strong>Note:</strong> As we see above, the string produced
297+ * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
298+ * occurrences of '{' are used to indicate subformats, and cause recursion.
299+ * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
300+ * programmatically (instead of using the string patterns), then be careful not to
301+ * produce a format that recurses on itself, which will cause an infinite loop.
302+ * <p>
303+ * When a single argument is parsed more than once in the string, the last match
304+ * will be the final result of the parsing. For example,
305+ * <blockquote><pre>
306+ * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
307+ * Object[] objs = {new Double(3.1415)};
308+ * String result = mf.format( objs );
309+ * // result now equals "3.14, 3.1"
310+ * objs = null;
311+ * objs = mf.parse(result, new ParsePosition(0));
312+ * // objs now equals {new Double(3.1)}
313+ * </pre></blockquote>
314+ *
315+ * <p>
316+ * Likewise, parsing with a {@code MessageFormat} object using patterns containing
317+ * multiple occurrences of the same argument would return the last match. For
318+ * example,
319+ * <blockquote><pre>
320+ * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
321+ * String forParsing = "x, y, z";
322+ * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
323+ * // result now equals {new String("z")}
324+ * </pre></blockquote>
325+ *
326+ * <h4><a name="synchronization">Synchronization</a></h4>
327+ *
328+ * <p>
329+ * Message formats are not synchronized.
330+ * It is recommended to create separate format instances for each thread.
331+ * If multiple threads access a format concurrently, it must be synchronized
332+ * externally.
333+ *
334+ * @see java.util.Locale
335+ * @see Format
336+ * @see NumberFormat
337+ * @see DecimalFormat
338+ * @see DecimalFormatSymbols
339+ * @see ChoiceFormat
340+ * @see DateFormat
341+ * @see SimpleDateFormat
342+ *
343+ * @author Mark Davis
344+ */
345+
346+public class MessageFormat extends Format {
347+
348+ private static final long serialVersionUID = 6479157306784022952L;
349+
350+ /**
351+ * Constructs a MessageFormat for the default locale and the
352+ * specified pattern.
353+ * The constructor first sets the locale, then parses the pattern and
354+ * creates a list of subformats for the format elements contained in it.
355+ * Patterns and their interpretation are specified in the
356+ * <a href="#patterns">class description</a>.
357+ *
358+ * @param pattern the pattern for this message format
359+ * @exception IllegalArgumentException if the pattern is invalid
360+ */
361+ public MessageFormat(String pattern) {
362+ this.locale = Locale.getDefault(Locale.Category.FORMAT);
363+ applyPattern(pattern);
364+ }
365+
366+ /**
367+ * Constructs a MessageFormat for the specified locale and
368+ * pattern.
369+ * The constructor first sets the locale, then parses the pattern and
370+ * creates a list of subformats for the format elements contained in it.
371+ * Patterns and their interpretation are specified in the
372+ * <a href="#patterns">class description</a>.
373+ *
374+ * @param pattern the pattern for this message format
375+ * @param locale the locale for this message format
376+ * @exception IllegalArgumentException if the pattern is invalid
377+ * @since 1.4
378+ */
379+ public MessageFormat(String pattern, Locale locale) {
380+ this.locale = locale;
381+ applyPattern(pattern);
382+ }
383+
384+ /**
385+ * Sets the locale to be used when creating or comparing subformats.
386+ * This affects subsequent calls
387+ * <ul>
388+ * <li>to the {@link #applyPattern applyPattern}
389+ * and {@link #toPattern toPattern} methods if format elements specify
390+ * a format type and therefore have the subformats created in the
391+ * <code>applyPattern</code> method, as well as
392+ * <li>to the <code>format</code> and
393+ * {@link #formatToCharacterIterator formatToCharacterIterator} methods
394+ * if format elements do not specify a format type and therefore have
395+ * the subformats created in the formatting methods.
396+ * </ul>
397+ * Subformats that have already been created are not affected.
398+ *
399+ * @param locale the locale to be used when creating or comparing subformats
400+ */
401+ public void setLocale(Locale locale) {
402+ this.locale = locale;
403+ }
404+
405+ /**
406+ * Gets the locale that's used when creating or comparing subformats.
407+ *
408+ * @return the locale used when creating or comparing subformats
409+ */
410+ public Locale getLocale() {
411+ return locale;
412+ }
413+
414+
415+ /**
416+ * Sets the pattern used by this message format.
417+ * The method parses the pattern and creates a list of subformats
418+ * for the format elements contained in it.
419+ * Patterns and their interpretation are specified in the
420+ * <a href="#patterns">class description</a>.
421+ *
422+ * @param pattern the pattern for this message format
423+ * @exception IllegalArgumentException if the pattern is invalid
424+ */
425+ public void applyPattern(String pattern) {
426+ StringBuilder[] segments = new StringBuilder[4];
427+ // Allocate only segments[SEG_RAW] here. The rest are
428+ // allocated on demand.
429+ segments[SEG_RAW] = new StringBuilder();
430+
431+ int part = SEG_RAW;
432+ int formatNumber = 0;
433+ boolean inQuote = false;
434+ int braceStack = 0;
435+ maxOffset = -1;
436+ for (int i = 0; i < pattern.length(); ++i) {
437+ char ch = pattern.charAt(i);
438+ if (part == SEG_RAW) {
439+ if (ch == '\'') {
440+ if (i + 1 < pattern.length()
441+ && pattern.charAt(i+1) == '\'') {
442+ segments[part].append(ch); // handle doubles
443+ ++i;
444+ } else {
445+ inQuote = !inQuote;
446+ }
447+ } else if (ch == '{' && !inQuote) {
448+ part = SEG_INDEX;
449+ if (segments[SEG_INDEX] == null) {
450+ segments[SEG_INDEX] = new StringBuilder();
451+ }
452+ } else {
453+ segments[part].append(ch);
454+ }
455+ } else {
456+ if (inQuote) { // just copy quotes in parts
457+ segments[part].append(ch);
458+ if (ch == '\'') {
459+ inQuote = false;
460+ }
461+ } else {
462+ switch (ch) {
463+ case ',':
464+ if (part < SEG_MODIFIER) {
465+ if (segments[++part] == null) {
466+ segments[part] = new StringBuilder();
467+ }
468+ } else {
469+ segments[part].append(ch);
470+ }
471+ break;
472+ case '{':
473+ ++braceStack;
474+ segments[part].append(ch);
475+ break;
476+ case '}':
477+ if (braceStack == 0) {
478+ part = SEG_RAW;
479+ makeFormat(i, formatNumber, segments);
480+ formatNumber++;
481+ // throw away other segments
482+ segments[SEG_INDEX] = null;
483+ segments[SEG_TYPE] = null;
484+ segments[SEG_MODIFIER] = null;
485+ } else {
486+ --braceStack;
487+ segments[part].append(ch);
488+ }
489+ break;
490+ case ' ':
491+ // Skip any leading space chars for SEG_TYPE.
492+ if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
493+ segments[part].append(ch);
494+ }
495+ break;
496+ case '\'':
497+ inQuote = true;
498+ // fall through, so we keep quotes in other parts
499+ default:
500+ segments[part].append(ch);
501+ break;
502+ }
503+ }
504+ }
505+ }
506+ if (braceStack == 0 && part != 0) {
507+ maxOffset = -1;
508+ throw new IllegalArgumentException("Unmatched braces in the pattern.");
509+ }
510+ this.pattern = segments[0].toString();
511+ }
512+
513+
514+ /**
515+ * Returns a pattern representing the current state of the message format.
516+ * The string is constructed from internal information and therefore
517+ * does not necessarily equal the previously applied pattern.
518+ *
519+ * @return a pattern representing the current state of the message format
520+ */
521+ public String toPattern() {
522+ // later, make this more extensible
523+ int lastOffset = 0;
524+ StringBuilder result = new StringBuilder();
525+ for (int i = 0; i <= maxOffset; ++i) {
526+ copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
527+ lastOffset = offsets[i];
528+ result.append('{').append(argumentNumbers[i]);
529+ Format fmt = formats[i];
530+ if (fmt == null) {
531+ // do nothing, string format
532+ } else if (fmt instanceof NumberFormat) {
533+ if (fmt.equals(NumberFormat.getInstance(locale))) {
534+ result.append(",number");
535+ } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
536+ result.append(",number,currency");
537+ } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
538+ result.append(",number,percent");
539+ } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
540+ result.append(",number,integer");
541+ } else {
542+ if (fmt instanceof DecimalFormat) {
543+ result.append(",number,").append(((DecimalFormat)fmt).toPattern());
544+ } else if (fmt instanceof ChoiceFormat) {
545+ result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
546+ } else {
547+ // UNKNOWN
548+ }
549+ }
550+ } else if (fmt instanceof DateFormat) {
551+ int index;
552+ for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
553+ DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
554+ locale);
555+ if (fmt.equals(df)) {
556+ result.append(",date");
557+ break;
558+ }
559+ df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
560+ locale);
561+ if (fmt.equals(df)) {
562+ result.append(",time");
563+ break;
564+ }
565+ }
566+ if (index >= DATE_TIME_MODIFIERS.length) {
567+ if (fmt instanceof SimpleDateFormat) {
568+ result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
569+ } else {
570+ // UNKNOWN
571+ }
572+ } else if (index != MODIFIER_DEFAULT) {
573+ result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
574+ }
575+ } else {
576+ //result.append(", unknown");
577+ }
578+ result.append('}');
579+ }
580+ copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
581+ return result.toString();
582+ }
583+
584+ /**
585+ * Sets the formats to use for the values passed into
586+ * <code>format</code> methods or returned from <code>parse</code>
587+ * methods. The indices of elements in <code>newFormats</code>
588+ * correspond to the argument indices used in the previously set
589+ * pattern string.
590+ * The order of formats in <code>newFormats</code> thus corresponds to
591+ * the order of elements in the <code>arguments</code> array passed
592+ * to the <code>format</code> methods or the result array returned
593+ * by the <code>parse</code> methods.
594+ * <p>
595+ * If an argument index is used for more than one format element
596+ * in the pattern string, then the corresponding new format is used
597+ * for all such format elements. If an argument index is not used
598+ * for any format element in the pattern string, then the
599+ * corresponding new format is ignored. If fewer formats are provided
600+ * than needed, then only the formats for argument indices less
601+ * than <code>newFormats.length</code> are replaced.
602+ *
603+ * @param newFormats the new formats to use
604+ * @exception NullPointerException if <code>newFormats</code> is null
605+ * @since 1.4
606+ */
607+ public void setFormatsByArgumentIndex(Format[] newFormats) {
608+ for (int i = 0; i <= maxOffset; i++) {
609+ int j = argumentNumbers[i];
610+ if (j < newFormats.length) {
611+ formats[i] = newFormats[j];
612+ }
613+ }
614+ }
615+
616+ /**
617+ * Sets the formats to use for the format elements in the
618+ * previously set pattern string.
619+ * The order of formats in <code>newFormats</code> corresponds to
620+ * the order of format elements in the pattern string.
621+ * <p>
622+ * If more formats are provided than needed by the pattern string,
623+ * the remaining ones are ignored. If fewer formats are provided
624+ * than needed, then only the first <code>newFormats.length</code>
625+ * formats are replaced.
626+ * <p>
627+ * Since the order of format elements in a pattern string often
628+ * changes during localization, it is generally better to use the
629+ * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
630+ * method, which assumes an order of formats corresponding to the
631+ * order of elements in the <code>arguments</code> array passed to
632+ * the <code>format</code> methods or the result array returned by
633+ * the <code>parse</code> methods.
634+ *
635+ * @param newFormats the new formats to use
636+ * @exception NullPointerException if <code>newFormats</code> is null
637+ */
638+ public void setFormats(Format[] newFormats) {
639+ int runsToCopy = newFormats.length;
640+ if (runsToCopy > maxOffset + 1) {
641+ runsToCopy = maxOffset + 1;
642+ }
643+ for (int i = 0; i < runsToCopy; i++) {
644+ formats[i] = newFormats[i];
645+ }
646+ }
647+
648+ /**
649+ * Sets the format to use for the format elements within the
650+ * previously set pattern string that use the given argument
651+ * index.
652+ * The argument index is part of the format element definition and
653+ * represents an index into the <code>arguments</code> array passed
654+ * to the <code>format</code> methods or the result array returned
655+ * by the <code>parse</code> methods.
656+ * <p>
657+ * If the argument index is used for more than one format element
658+ * in the pattern string, then the new format is used for all such
659+ * format elements. If the argument index is not used for any format
660+ * element in the pattern string, then the new format is ignored.
661+ *
662+ * @param argumentIndex the argument index for which to use the new format
663+ * @param newFormat the new format to use
664+ * @since 1.4
665+ */
666+ public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
667+ for (int j = 0; j <= maxOffset; j++) {
668+ if (argumentNumbers[j] == argumentIndex) {
669+ formats[j] = newFormat;
670+ }
671+ }
672+ }
673+
674+ /**
675+ * Sets the format to use for the format element with the given
676+ * format element index within the previously set pattern string.
677+ * The format element index is the zero-based number of the format
678+ * element counting from the start of the pattern string.
679+ * <p>
680+ * Since the order of format elements in a pattern string often
681+ * changes during localization, it is generally better to use the
682+ * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
683+ * method, which accesses format elements based on the argument
684+ * index they specify.
685+ *
686+ * @param formatElementIndex the index of a format element within the pattern
687+ * @param newFormat the format to use for the specified format element
688+ * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
689+ * larger than the number of format elements in the pattern string
690+ */
691+ public void setFormat(int formatElementIndex, Format newFormat) {
692+ formats[formatElementIndex] = newFormat;
693+ }
694+
695+ /**
696+ * Gets the formats used for the values passed into
697+ * <code>format</code> methods or returned from <code>parse</code>
698+ * methods. The indices of elements in the returned array
699+ * correspond to the argument indices used in the previously set
700+ * pattern string.
701+ * The order of formats in the returned array thus corresponds to
702+ * the order of elements in the <code>arguments</code> array passed
703+ * to the <code>format</code> methods or the result array returned
704+ * by the <code>parse</code> methods.
705+ * <p>
706+ * If an argument index is used for more than one format element
707+ * in the pattern string, then the format used for the last such
708+ * format element is returned in the array. If an argument index
709+ * is not used for any format element in the pattern string, then
710+ * null is returned in the array.
711+ *
712+ * @return the formats used for the arguments within the pattern
713+ * @since 1.4
714+ */
715+ public Format[] getFormatsByArgumentIndex() {
716+ int maximumArgumentNumber = -1;
717+ for (int i = 0; i <= maxOffset; i++) {
718+ if (argumentNumbers[i] > maximumArgumentNumber) {
719+ maximumArgumentNumber = argumentNumbers[i];
720+ }
721+ }
722+ Format[] resultArray = new Format[maximumArgumentNumber + 1];
723+ for (int i = 0; i <= maxOffset; i++) {
724+ resultArray[argumentNumbers[i]] = formats[i];
725+ }
726+ return resultArray;
727+ }
728+
729+ /**
730+ * Gets the formats used for the format elements in the
731+ * previously set pattern string.
732+ * The order of formats in the returned array corresponds to
733+ * the order of format elements in the pattern string.
734+ * <p>
735+ * Since the order of format elements in a pattern string often
736+ * changes during localization, it's generally better to use the
737+ * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
738+ * method, which assumes an order of formats corresponding to the
739+ * order of elements in the <code>arguments</code> array passed to
740+ * the <code>format</code> methods or the result array returned by
741+ * the <code>parse</code> methods.
742+ *
743+ * @return the formats used for the format elements in the pattern
744+ */
745+ public Format[] getFormats() {
746+ Format[] resultArray = new Format[maxOffset + 1];
747+ System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
748+ return resultArray;
749+ }
750+
751+ /**
752+ * Formats an array of objects and appends the <code>MessageFormat</code>'s
753+ * pattern, with format elements replaced by the formatted objects, to the
754+ * provided <code>StringBuffer</code>.
755+ * <p>
756+ * The text substituted for the individual format elements is derived from
757+ * the current subformat of the format element and the
758+ * <code>arguments</code> element at the format element's argument index
759+ * as indicated by the first matching line of the following table. An
760+ * argument is <i>unavailable</i> if <code>arguments</code> is
761+ * <code>null</code> or has fewer than argumentIndex+1 elements.
762+ * <p>
763+ * <table border=1 summary="Examples of subformat,argument,and formatted text">
764+ * <tr>
765+ * <th>Subformat
766+ * <th>Argument
767+ * <th>Formatted Text
768+ * <tr>
769+ * <td><i>any</i>
770+ * <td><i>unavailable</i>
771+ * <td><code>"{" + argumentIndex + "}"</code>
772+ * <tr>
773+ * <td><i>any</i>
774+ * <td><code>null</code>
775+ * <td><code>"null"</code>
776+ * <tr>
777+ * <td><code>instanceof ChoiceFormat</code>
778+ * <td><i>any</i>
779+ * <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
780+ * (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
781+ * subformat.format(argument)</code>
782+ * <tr>
783+ * <td><code>!= null</code>
784+ * <td><i>any</i>
785+ * <td><code>subformat.format(argument)</code>
786+ * <tr>
787+ * <td><code>null</code>
788+ * <td><code>instanceof Number</code>
789+ * <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
790+ * <tr>
791+ * <td><code>null</code>
792+ * <td><code>instanceof Date</code>
793+ * <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
794+ * <tr>
795+ * <td><code>null</code>
796+ * <td><code>instanceof String</code>
797+ * <td><code>argument</code>
798+ * <tr>
799+ * <td><code>null</code>
800+ * <td><i>any</i>
801+ * <td><code>argument.toString()</code>
802+ * </table>
803+ * <p>
804+ * If <code>pos</code> is non-null, and refers to
805+ * <code>Field.ARGUMENT</code>, the location of the first formatted
806+ * string will be returned.
807+ *
808+ * @param arguments an array of objects to be formatted and substituted.
809+ * @param result where text is appended.
810+ * @param pos On input: an alignment field, if desired.
811+ * On output: the offsets of the alignment field.
812+ * @exception IllegalArgumentException if an argument in the
813+ * <code>arguments</code> array is not of the type
814+ * expected by the format element(s) that use it.
815+ */
816+ public final StringBuffer format(Object[] arguments, StringBuffer result,
817+ FieldPosition pos)
818+ {
819+ return subformat(arguments, result, pos, null);
820+ }
821+
822+ /**
823+ * Creates a MessageFormat with the given pattern and uses it
824+ * to format the given arguments. This is equivalent to
825+ * <blockquote>
826+ * <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
827+ * </blockquote>
828+ *
829+ * @exception IllegalArgumentException if the pattern is invalid,
830+ * or if an argument in the <code>arguments</code> array
831+ * is not of the type expected by the format element(s)
832+ * that use it.
833+ */
834+ public static String format(String pattern, Object ... arguments) {
835+ MessageFormat temp = new MessageFormat(pattern);
836+ return temp.format(arguments);
837+ }
838+
839+ // Overrides
840+ /**
841+ * Formats an array of objects and appends the <code>MessageFormat</code>'s
842+ * pattern, with format elements replaced by the formatted objects, to the
843+ * provided <code>StringBuffer</code>.
844+ * This is equivalent to
845+ * <blockquote>
846+ * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
847+ * </blockquote>
848+ *
849+ * @param arguments an array of objects to be formatted and substituted.
850+ * @param result where text is appended.
851+ * @param pos On input: an alignment field, if desired.
852+ * On output: the offsets of the alignment field.
853+ * @exception IllegalArgumentException if an argument in the
854+ * <code>arguments</code> array is not of the type
855+ * expected by the format element(s) that use it.
856+ */
857+ public final StringBuffer format(Object arguments, StringBuffer result,
858+ FieldPosition pos)
859+ {
860+ return subformat((Object[]) arguments, result, pos, null);
861+ }
862+
863+ /**
864+ * Formats an array of objects and inserts them into the
865+ * <code>MessageFormat</code>'s pattern, producing an
866+ * <code>AttributedCharacterIterator</code>.
867+ * You can use the returned <code>AttributedCharacterIterator</code>
868+ * to build the resulting String, as well as to determine information
869+ * about the resulting String.
870+ * <p>
871+ * The text of the returned <code>AttributedCharacterIterator</code> is
872+ * the same that would be returned by
873+ * <blockquote>
874+ * <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
875+ * </blockquote>
876+ * <p>
877+ * In addition, the <code>AttributedCharacterIterator</code> contains at
878+ * least attributes indicating where text was generated from an
879+ * argument in the <code>arguments</code> array. The keys of these attributes are of
880+ * type <code>MessageFormat.Field</code>, their values are
881+ * <code>Integer</code> objects indicating the index in the <code>arguments</code>
882+ * array of the argument from which the text was generated.
883+ * <p>
884+ * The attributes/value from the underlying <code>Format</code>
885+ * instances that <code>MessageFormat</code> uses will also be
886+ * placed in the resulting <code>AttributedCharacterIterator</code>.
887+ * This allows you to not only find where an argument is placed in the
888+ * resulting String, but also which fields it contains in turn.
889+ *
890+ * @param arguments an array of objects to be formatted and substituted.
891+ * @return AttributedCharacterIterator describing the formatted value.
892+ * @exception NullPointerException if <code>arguments</code> is null.
893+ * @exception IllegalArgumentException if an argument in the
894+ * <code>arguments</code> array is not of the type
895+ * expected by the format element(s) that use it.
896+ * @since 1.4
897+ */
898+ public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
899+ StringBuffer result = new StringBuffer();
900+ ArrayList iterators = new ArrayList();
901+
902+ if (arguments == null) {
903+ throw new NullPointerException(
904+ "formatToCharacterIterator must be passed non-null object");
905+ }
906+ subformat((Object[]) arguments, result, null, iterators);
907+ if (iterators.size() == 0) {
908+ return createAttributedCharacterIterator("");
909+ }
910+ return createAttributedCharacterIterator(
911+ (AttributedCharacterIterator[])iterators.toArray(
912+ new AttributedCharacterIterator[iterators.size()]));
913+ }
914+
915+ /**
916+ * Parses the string.
917+ *
918+ * <p>Caveats: The parse may fail in a number of circumstances.
919+ * For example:
920+ * <ul>
921+ * <li>If one of the arguments does not occur in the pattern.
922+ * <li>If the format of an argument loses information, such as
923+ * with a choice format where a large number formats to "many".
924+ * <li>Does not yet handle recursion (where
925+ * the substituted strings contain {n} references.)
926+ * <li>Will not always find a match (or the correct match)
927+ * if some part of the parse is ambiguous.
928+ * For example, if the pattern "{1},{2}" is used with the
929+ * string arguments {"a,b", "c"}, it will format as "a,b,c".
930+ * When the result is parsed, it will return {"a", "b,c"}.
931+ * <li>If a single argument is parsed more than once in the string,
932+ * then the later parse wins.
933+ * </ul>
934+ * When the parse fails, use ParsePosition.getErrorIndex() to find out
935+ * where in the string the parsing failed. The returned error
936+ * index is the starting offset of the sub-patterns that the string
937+ * is comparing with. For example, if the parsing string "AAA {0} BBB"
938+ * is comparing against the pattern "AAD {0} BBB", the error index is
939+ * 0. When an error occurs, the call to this method will return null.
940+ * If the source is null, return an empty array.
941+ */
942+ public Object[] parse(String source, ParsePosition pos) {
943+ if (source == null) {
944+ Object[] empty = {};
945+ return empty;
946+ }
947+
948+ int maximumArgumentNumber = -1;
949+ for (int i = 0; i <= maxOffset; i++) {
950+ if (argumentNumbers[i] > maximumArgumentNumber) {
951+ maximumArgumentNumber = argumentNumbers[i];
952+ }
953+ }
954+ Object[] resultArray = new Object[maximumArgumentNumber + 1];
955+
956+ int patternOffset = 0;
957+ int sourceOffset = pos.index;
958+ ParsePosition tempStatus = new ParsePosition(0);
959+ for (int i = 0; i <= maxOffset; ++i) {
960+ // match up to format
961+ int len = offsets[i] - patternOffset;
962+ if (len == 0 || pattern.regionMatches(patternOffset,
963+ source, sourceOffset, len)) {
964+ sourceOffset += len;
965+ patternOffset += len;
966+ } else {
967+ pos.errorIndex = sourceOffset;
968+ return null; // leave index as is to signal error
969+ }
970+
971+ // now use format
972+ if (formats[i] == null) { // string format
973+ // if at end, use longest possible match
974+ // otherwise uses first match to intervening string
975+ // does NOT recursively try all possibilities
976+ int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
977+
978+ int next;
979+ if (patternOffset >= tempLength) {
980+ next = source.length();
981+ }else{
982+ next = source.indexOf(pattern.substring(patternOffset, tempLength),
983+ sourceOffset);
984+ }
985+
986+ if (next < 0) {
987+ pos.errorIndex = sourceOffset;
988+ return null; // leave index as is to signal error
989+ } else {
990+ String strValue= source.substring(sourceOffset,next);
991+ if (!strValue.equals("{"+argumentNumbers[i]+"}"))
992+ resultArray[argumentNumbers[i]]
993+ = source.substring(sourceOffset,next);
994+ sourceOffset = next;
995+ }
996+ } else {
997+ tempStatus.index = sourceOffset;
998+ resultArray[argumentNumbers[i]]
999+ = formats[i].parseObject(source,tempStatus);
1000+ if (tempStatus.index == sourceOffset) {
1001+ pos.errorIndex = sourceOffset;
1002+ return null; // leave index as is to signal error
1003+ }
1004+ sourceOffset = tempStatus.index; // update
1005+ }
1006+ }
1007+ int len = pattern.length() - patternOffset;
1008+ if (len == 0 || pattern.regionMatches(patternOffset,
1009+ source, sourceOffset, len)) {
1010+ pos.index = sourceOffset + len;
1011+ } else {
1012+ pos.errorIndex = sourceOffset;
1013+ return null; // leave index as is to signal error
1014+ }
1015+ return resultArray;
1016+ }
1017+
1018+ /**
1019+ * Parses text from the beginning of the given string to produce an object
1020+ * array.
1021+ * The method may not use the entire text of the given string.
1022+ * <p>
1023+ * See the {@link #parse(String, ParsePosition)} method for more information
1024+ * on message parsing.
1025+ *
1026+ * @param source A <code>String</code> whose beginning should be parsed.
1027+ * @return An <code>Object</code> array parsed from the string.
1028+ * @exception ParseException if the beginning of the specified string
1029+ * cannot be parsed.
1030+ */
1031+ public Object[] parse(String source) throws ParseException {
1032+ ParsePosition pos = new ParsePosition(0);
1033+ Object[] result = parse(source, pos);
1034+ if (pos.index == 0) // unchanged, returned object is null
1035+ throw new ParseException("MessageFormat parse error!", pos.errorIndex);
1036+
1037+ return result;
1038+ }
1039+
1040+ /**
1041+ * Parses text from a string to produce an object array.
1042+ * <p>
1043+ * The method attempts to parse text starting at the index given by
1044+ * <code>pos</code>.
1045+ * If parsing succeeds, then the index of <code>pos</code> is updated
1046+ * to the index after the last character used (parsing does not necessarily
1047+ * use all characters up to the end of the string), and the parsed
1048+ * object array is returned. The updated <code>pos</code> can be used to
1049+ * indicate the starting point for the next call to this method.
1050+ * If an error occurs, then the index of <code>pos</code> is not
1051+ * changed, the error index of <code>pos</code> is set to the index of
1052+ * the character where the error occurred, and null is returned.
1053+ * <p>
1054+ * See the {@link #parse(String, ParsePosition)} method for more information
1055+ * on message parsing.
1056+ *
1057+ * @param source A <code>String</code>, part of which should be parsed.
1058+ * @param pos A <code>ParsePosition</code> object with index and error
1059+ * index information as described above.
1060+ * @return An <code>Object</code> array parsed from the string. In case of
1061+ * error, returns null.
1062+ * @exception NullPointerException if <code>pos</code> is null.
1063+ */
1064+ public Object parseObject(String source, ParsePosition pos) {
1065+ return parse(source, pos);
1066+ }
1067+
1068+ /**
1069+ * Creates and returns a copy of this object.
1070+ *
1071+ * @return a clone of this instance.
1072+ */
1073+ public Object clone() {
1074+ MessageFormat other = (MessageFormat) super.clone();
1075+
1076+ // clone arrays. Can't do with utility because of bug in Cloneable
1077+ other.formats = (Format[]) formats.clone(); // shallow clone
1078+ for (int i = 0; i < formats.length; ++i) {
1079+ if (formats[i] != null)
1080+ other.formats[i] = (Format)formats[i].clone();
1081+ }
1082+ // for primitives or immutables, shallow clone is enough
1083+ other.offsets = (int[]) offsets.clone();
1084+ other.argumentNumbers = (int[]) argumentNumbers.clone();
1085+
1086+ return other;
1087+ }
1088+
1089+ /**
1090+ * Equality comparison between two message format objects
1091+ */
1092+ public boolean equals(Object obj) {
1093+ if (this == obj) // quick check
1094+ return true;
1095+ if (obj == null || getClass() != obj.getClass())
1096+ return false;
1097+ MessageFormat other = (MessageFormat) obj;
1098+ return (maxOffset == other.maxOffset
1099+ && pattern.equals(other.pattern)
1100+ && ((locale != null && locale.equals(other.locale))
1101+ || (locale == null && other.locale == null))
1102+ && Arrays.equals(offsets,other.offsets)
1103+ && Arrays.equals(argumentNumbers,other.argumentNumbers)
1104+ && Arrays.equals(formats,other.formats));
1105+ }
1106+
1107+ /**
1108+ * Generates a hash code for the message format object.
1109+ */
1110+ public int hashCode() {
1111+ return pattern.hashCode(); // enough for reasonable distribution
1112+ }
1113+
1114+
1115+ /**
1116+ * Defines constants that are used as attribute keys in the
1117+ * <code>AttributedCharacterIterator</code> returned
1118+ * from <code>MessageFormat.formatToCharacterIterator</code>.
1119+ *
1120+ * @since 1.4
1121+ */
1122+ public static class Field extends Format.Field {
1123+
1124+ // Proclaim serial compatibility with 1.4 FCS
1125+ private static final long serialVersionUID = 7899943957617360810L;
1126+
1127+ /**
1128+ * Creates a Field with the specified name.
1129+ *
1130+ * @param name Name of the attribute
1131+ */
1132+ protected Field(String name) {
1133+ super(name);
1134+ }
1135+
1136+ /**
1137+ * Resolves instances being deserialized to the predefined constants.
1138+ *
1139+ * @throws InvalidObjectException if the constant could not be
1140+ * resolved.
1141+ * @return resolved MessageFormat.Field constant
1142+ */
1143+ protected Object readResolve() throws InvalidObjectException {
1144+ if (this.getClass() != MessageFormat.Field.class) {
1145+ throw new InvalidObjectException("subclass didn't correctly implement readResolve");
1146+ }
1147+
1148+ return ARGUMENT;
1149+ }
1150+
1151+ //
1152+ // The constants
1153+ //
1154+
1155+ /**
1156+ * Constant identifying a portion of a message that was generated
1157+ * from an argument passed into <code>formatToCharacterIterator</code>.
1158+ * The value associated with the key will be an <code>Integer</code>
1159+ * indicating the index in the <code>arguments</code> array of the
1160+ * argument from which the text was generated.
1161+ */
1162+ public final static Field ARGUMENT =
1163+ new Field("message argument field");
1164+ }
1165+
1166+ // ===========================privates============================
1167+
1168+ /**
1169+ * The locale to use for formatting numbers and dates.
1170+ * @serial
1171+ */
1172+ private Locale locale;
1173+
1174+ /**
1175+ * The string that the formatted values are to be plugged into. In other words, this
1176+ * is the pattern supplied on construction with all of the {} expressions taken out.
1177+ * @serial
1178+ */
1179+ private String pattern = "";
1180+
1181+ /** The initially expected number of subformats in the format */
1182+ private static final int INITIAL_FORMATS = 10;
1183+
1184+ /**
1185+ * An array of formatters, which are used to format the arguments.
1186+ * @serial
1187+ */
1188+ private Format[] formats = new Format[INITIAL_FORMATS];
1189+
1190+ /**
1191+ * The positions where the results of formatting each argument are to be inserted
1192+ * into the pattern.
1193+ * @serial
1194+ */
1195+ private int[] offsets = new int[INITIAL_FORMATS];
1196+
1197+ /**
1198+ * The argument numbers corresponding to each formatter. (The formatters are stored
1199+ * in the order they occur in the pattern, not in the order in which the arguments
1200+ * are specified.)
1201+ * @serial
1202+ */
1203+ private int[] argumentNumbers = new int[INITIAL_FORMATS];
1204+
1205+ /**
1206+ * One less than the number of entries in <code>offsets</code>. Can also be thought of
1207+ * as the index of the highest-numbered element in <code>offsets</code> that is being used.
1208+ * All of these arrays should have the same number of elements being used as <code>offsets</code>
1209+ * does, and so this variable suffices to tell us how many entries are in all of them.
1210+ * @serial
1211+ */
1212+ private int maxOffset = -1;
1213+
1214+ /**
1215+ * Internal routine used by format. If <code>characterIterators</code> is
1216+ * non-null, AttributedCharacterIterator will be created from the
1217+ * subformats as necessary. If <code>characterIterators</code> is null
1218+ * and <code>fp</code> is non-null and identifies
1219+ * <code>Field.MESSAGE_ARGUMENT</code>, the location of
1220+ * the first replaced argument will be set in it.
1221+ *
1222+ * @exception IllegalArgumentException if an argument in the
1223+ * <code>arguments</code> array is not of the type
1224+ * expected by the format element(s) that use it.
1225+ */
1226+ private StringBuffer subformat(Object[] arguments, StringBuffer result,
1227+ FieldPosition fp, List characterIterators) {
1228+ // note: this implementation assumes a fast substring & index.
1229+ // if this is not true, would be better to append chars one by one.
1230+ int lastOffset = 0;
1231+ int last = result.length();
1232+ for (int i = 0; i <= maxOffset; ++i) {
1233+ result.append(pattern.substring(lastOffset, offsets[i]));
1234+ lastOffset = offsets[i];
1235+ int argumentNumber = argumentNumbers[i];
1236+ if (arguments == null || argumentNumber >= arguments.length) {
1237+ result.append('{').append(argumentNumber).append('}');
1238+ continue;
1239+ }
1240+ // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
1241+ if (false) { // if (argRecursion == 3){
1242+ // prevent loop!!!
1243+ result.append('\uFFFD');
1244+ } else {
1245+ Object obj = arguments[argumentNumber];
1246+ String arg = null;
1247+ Format subFormatter = null;
1248+ if (obj == null) {
1249+ arg = "null";
1250+ } else if (formats[i] != null) {
1251+ subFormatter = formats[i];
1252+ if (subFormatter instanceof ChoiceFormat) {
1253+ arg = formats[i].format(obj);
1254+ if (arg.indexOf('{') >= 0) {
1255+ subFormatter = new MessageFormat(arg, locale);
1256+ obj = arguments;
1257+ arg = null;
1258+ }
1259+ }
1260+ } else if (obj instanceof Number) {
1261+ // format number if can
1262+ subFormatter = NumberFormat.getInstance(locale);
1263+ } else if (obj instanceof Date) {
1264+ // format a Date if can
1265+ subFormatter = DateFormat.getDateTimeInstance(
1266+ DateFormat.SHORT, DateFormat.SHORT, locale);//fix
1267+ } else if (obj instanceof String) {
1268+ arg = (String) obj;
1269+
1270+ } else {
1271+ arg = obj.toString();
1272+ if (arg == null) arg = "null";
1273+ }
1274+
1275+ // At this point we are in two states, either subFormatter
1276+ // is non-null indicating we should format obj using it,
1277+ // or arg is non-null and we should use it as the value.
1278+
1279+ if (characterIterators != null) {
1280+ // If characterIterators is non-null, it indicates we need
1281+ // to get the CharacterIterator from the child formatter.
1282+ if (last != result.length()) {
1283+ characterIterators.add(
1284+ createAttributedCharacterIterator(result.substring
1285+ (last)));
1286+ last = result.length();
1287+ }
1288+ if (subFormatter != null) {
1289+ AttributedCharacterIterator subIterator =
1290+ subFormatter.formatToCharacterIterator(obj);
1291+
1292+ append(result, subIterator);
1293+ if (last != result.length()) {
1294+ characterIterators.add(
1295+ createAttributedCharacterIterator(
1296+ subIterator, Field.ARGUMENT,
1297+ Integer.valueOf(argumentNumber)));
1298+ last = result.length();
1299+ }
1300+ arg = null;
1301+ }
1302+ if (arg != null && arg.length() > 0) {
1303+ result.append(arg);
1304+ characterIterators.add(
1305+ createAttributedCharacterIterator(
1306+ arg, Field.ARGUMENT,
1307+ Integer.valueOf(argumentNumber)));
1308+ last = result.length();
1309+ }
1310+ }
1311+ else {
1312+ if (subFormatter != null) {
1313+ arg = subFormatter.format(obj);
1314+ }
1315+ last = result.length();
1316+ result.append(arg);
1317+ if (i == 0 && fp != null && Field.ARGUMENT.equals(
1318+ fp.getFieldAttribute())) {
1319+ fp.setBeginIndex(last);
1320+ fp.setEndIndex(result.length());
1321+ }
1322+ last = result.length();
1323+ }
1324+ }
1325+ }
1326+ result.append(pattern.substring(lastOffset, pattern.length()));
1327+ if (characterIterators != null && last != result.length()) {
1328+ characterIterators.add(createAttributedCharacterIterator(
1329+ result.substring(last)));
1330+ }
1331+ return result;
1332+ }
1333+
1334+ /**
1335+ * Convenience method to append all the characters in
1336+ * <code>iterator</code> to the StringBuffer <code>result</code>.
1337+ */
1338+ private void append(StringBuffer result, CharacterIterator iterator) {
1339+ if (iterator.first() != CharacterIterator.DONE) {
1340+ char aChar;
1341+
1342+ result.append(iterator.first());
1343+ while ((aChar = iterator.next()) != CharacterIterator.DONE) {
1344+ result.append(aChar);
1345+ }
1346+ }
1347+ }
1348+
1349+ // Indices for segments
1350+ private static final int SEG_RAW = 0;
1351+ private static final int SEG_INDEX = 1;
1352+ private static final int SEG_TYPE = 2;
1353+ private static final int SEG_MODIFIER = 3; // modifier or subformat
1354+
1355+ // Indices for type keywords
1356+ private static final int TYPE_NULL = 0;
1357+ private static final int TYPE_NUMBER = 1;
1358+ private static final int TYPE_DATE = 2;
1359+ private static final int TYPE_TIME = 3;
1360+ private static final int TYPE_CHOICE = 4;
1361+
1362+ private static final String[] TYPE_KEYWORDS = {
1363+ "",
1364+ "number",
1365+ "date",
1366+ "time",
1367+ "choice"
1368+ };
1369+
1370+ // Indices for number modifiers
1371+ private static final int MODIFIER_DEFAULT = 0; // common in number and date-time
1372+ private static final int MODIFIER_CURRENCY = 1;
1373+ private static final int MODIFIER_PERCENT = 2;
1374+ private static final int MODIFIER_INTEGER = 3;
1375+
1376+ private static final String[] NUMBER_MODIFIER_KEYWORDS = {
1377+ "",
1378+ "currency",
1379+ "percent",
1380+ "integer"
1381+ };
1382+
1383+ // Indices for date-time modifiers
1384+ private static final int MODIFIER_SHORT = 1;
1385+ private static final int MODIFIER_MEDIUM = 2;
1386+ private static final int MODIFIER_LONG = 3;
1387+ private static final int MODIFIER_FULL = 4;
1388+
1389+ private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
1390+ "",
1391+ "short",
1392+ "medium",
1393+ "long",
1394+ "full"
1395+ };
1396+
1397+ // Date-time style values corresponding to the date-time modifiers.
1398+ private static final int[] DATE_TIME_MODIFIERS = {
1399+ DateFormat.DEFAULT,
1400+ DateFormat.SHORT,
1401+ DateFormat.MEDIUM,
1402+ DateFormat.LONG,
1403+ DateFormat.FULL,
1404+ };
1405+
1406+ private void makeFormat(int position, int offsetNumber,
1407+ StringBuilder[] textSegments)
1408+ {
1409+ String[] segments = new String[textSegments.length];
1410+ for (int i = 0; i < textSegments.length; i++) {
1411+ StringBuilder oneseg = textSegments[i];
1412+ segments[i] = (oneseg != null) ? oneseg.toString() : "";
1413+ }
1414+
1415+ // get the argument number
1416+ int argumentNumber;
1417+ try {
1418+ argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
1419+ } catch (NumberFormatException e) {
1420+ throw new IllegalArgumentException("can't parse argument number: "
1421+ + segments[SEG_INDEX], e);
1422+ }
1423+ if (argumentNumber < 0) {
1424+ throw new IllegalArgumentException("negative argument number: "
1425+ + argumentNumber);
1426+ }
1427+
1428+ // resize format information arrays if necessary
1429+ if (offsetNumber >= formats.length) {
1430+ int newLength = formats.length * 2;
1431+ Format[] newFormats = new Format[newLength];
1432+ int[] newOffsets = new int[newLength];
1433+ int[] newArgumentNumbers = new int[newLength];
1434+ System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
1435+ System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
1436+ System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
1437+ formats = newFormats;
1438+ offsets = newOffsets;
1439+ argumentNumbers = newArgumentNumbers;
1440+ }
1441+ int oldMaxOffset = maxOffset;
1442+ maxOffset = offsetNumber;
1443+ offsets[offsetNumber] = segments[SEG_RAW].length();
1444+ argumentNumbers[offsetNumber] = argumentNumber;
1445+
1446+ // now get the format
1447+ Format newFormat = null;
1448+ if (segments[SEG_TYPE].length() != 0) {
1449+ int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
1450+ switch (type) {
1451+ case TYPE_NULL:
1452+ // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
1453+ // are treated as "{0}".
1454+ break;
1455+
1456+ case TYPE_NUMBER:
1457+ switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
1458+ case MODIFIER_DEFAULT:
1459+ newFormat = NumberFormat.getInstance(locale);
1460+ break;
1461+ case MODIFIER_CURRENCY:
1462+ newFormat = NumberFormat.getCurrencyInstance(locale);
1463+ break;
1464+ case MODIFIER_PERCENT:
1465+ newFormat = NumberFormat.getPercentInstance(locale);
1466+ break;
1467+ case MODIFIER_INTEGER:
1468+ newFormat = NumberFormat.getIntegerInstance(locale);
1469+ break;
1470+ default: // DecimalFormat pattern
1471+ try {
1472+ newFormat = new DecimalFormat(segments[SEG_MODIFIER],
1473+ DecimalFormatSymbols.getInstance(locale));
1474+ } catch (IllegalArgumentException e) {
1475+ maxOffset = oldMaxOffset;
1476+ throw e;
1477+ }
1478+ break;
1479+ }
1480+ break;
1481+
1482+ case TYPE_DATE:
1483+ case TYPE_TIME:
1484+ int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
1485+ if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
1486+ if (type == TYPE_DATE) {
1487+ newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
1488+ locale);
1489+ } else {
1490+ newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
1491+ locale);
1492+ }
1493+ } else {
1494+ // SimpleDateFormat pattern
1495+ try {
1496+ newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
1497+ } catch (IllegalArgumentException e) {
1498+ maxOffset = oldMaxOffset;
1499+ throw e;
1500+ }
1501+ }
1502+ break;
1503+
1504+ case TYPE_CHOICE:
1505+ try {
1506+ // ChoiceFormat pattern
1507+ newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
1508+ } catch (Exception e) {
1509+ maxOffset = oldMaxOffset;
1510+ throw new IllegalArgumentException("Choice Pattern incorrect: "
1511+ + segments[SEG_MODIFIER], e);
1512+ }
1513+ break;
1514+
1515+ default:
1516+ maxOffset = oldMaxOffset;
1517+ throw new IllegalArgumentException("unknown format type: " +
1518+ segments[SEG_TYPE]);
1519+ }
1520+ }
1521+ formats[offsetNumber] = newFormat;
1522+ }
1523+
1524+ private static final int findKeyword(String s, String[] list) {
1525+ for (int i = 0; i < list.length; ++i) {
1526+ if (s.equals(list[i]))
1527+ return i;
1528+ }
1529+
1530+ // Try trimmed lowercase.
1531+ String ls = s.trim().toLowerCase(Locale.ROOT);
1532+ if (ls != s) {
1533+ for (int i = 0; i < list.length; ++i) {
1534+ if (ls.equals(list[i]))
1535+ return i;
1536+ }
1537+ }
1538+ return -1;
1539+ }
1540+
1541+ private static final void copyAndFixQuotes(String source, int start, int end,
1542+ StringBuilder target) {
1543+ boolean quoted = false;
1544+
1545+ for (int i = start; i < end; ++i) {
1546+ char ch = source.charAt(i);
1547+ if (ch == '{') {
1548+ if (!quoted) {
1549+ target.append('\'');
1550+ quoted = true;
1551+ }
1552+ target.append(ch);
1553+ } else if (ch == '\'') {
1554+ target.append("''");
1555+ } else {
1556+ if (quoted) {
1557+ target.append('\'');
1558+ quoted = false;
1559+ }
1560+ target.append(ch);
1561+ }
1562+ }
1563+ if (quoted) {
1564+ target.append('\'');
1565+ }
1566+ }
1567+
1568+ /**
1569+ * After reading an object from the input stream, do a simple verification
1570+ * to maintain class invariants.
1571+ * @throws InvalidObjectException if the objects read from the stream is invalid.
1572+ */
1573+ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1574+ in.defaultReadObject();
1575+ boolean isValid = maxOffset >= -1
1576+ && formats.length > maxOffset
1577+ && offsets.length > maxOffset
1578+ && argumentNumbers.length > maxOffset;
1579+ if (isValid) {
1580+ int lastOffset = pattern.length() + 1;
1581+ for (int i = maxOffset; i >= 0; --i) {
1582+ if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
1583+ isValid = false;
1584+ break;
1585+ } else {
1586+ lastOffset = offsets[i];
1587+ }
1588+ }
1589+ }
1590+ if (!isValid) {
1591+ throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
1592+ }
1593+ }
1594+}
java/pkg/java/text/Normalizer$Form.class+0−0

Binary file not shown.

java/pkg/java/text/Normalizer.class+0−0

Binary file not shown.

java/pkg/java/text/Normalizer.java+183−0
@@ -0,0 +1,183 @@
1+/*
2+ * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ *******************************************************************************
28+ * (C) Copyright IBM Corp. 1996-2005 - All Rights Reserved *
29+ * *
30+ * The original version of this source code and documentation is copyrighted *
31+ * and owned by IBM, These materials are provided under terms of a License *
32+ * Agreement between IBM and Sun. This technology is protected by multiple *
33+ * US and International patents. This notice and attribution to IBM may not *
34+ * to removed. *
35+ *******************************************************************************
36+ */
37+
38+package java.text;
39+
40+import sun.text.normalizer.NormalizerBase;
41+import sun.text.normalizer.NormalizerImpl;
42+
43+/**
44+ * This class provides the method <code>normalize</code> which transforms Unicode
45+ * text into an equivalent composed or decomposed form, allowing for easier
46+ * sorting and searching of text.
47+ * The <code>normalize</code> method supports the standard normalization forms
48+ * described in
49+ * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">
50+ * Unicode Standard Annex #15 &mdash; Unicode Normalization Forms</a>.
51+ * <p>
52+ * Characters with accents or other adornments can be encoded in
53+ * several different ways in Unicode. For example, take the character A-acute.
54+ * In Unicode, this can be encoded as a single character (the "composed" form):
55+ *
56+ * <p><pre>
57+ * U+00C1 LATIN CAPITAL LETTER A WITH ACUTE</pre>
58+ * </p>
59+ *
60+ * or as two separate characters (the "decomposed" form):
61+ *
62+ * <p><pre>
63+ * U+0041 LATIN CAPITAL LETTER A
64+ * U+0301 COMBINING ACUTE ACCENT</pre>
65+ * </p>
66+ *
67+ * To a user of your program, however, both of these sequences should be
68+ * treated as the same "user-level" character "A with acute accent". When you
69+ * are searching or comparing text, you must ensure that these two sequences are
70+ * treated as equivalent. In addition, you must handle characters with more than
71+ * one accent. Sometimes the order of a character's combining accents is
72+ * significant, while in other cases accent sequences in different orders are
73+ * really equivalent.
74+ * <p>
75+ * Similarly, the string "ffi" can be encoded as three separate letters:
76+ *
77+ * <p><pre>
78+ * U+0066 LATIN SMALL LETTER F
79+ * U+0066 LATIN SMALL LETTER F
80+ * U+0069 LATIN SMALL LETTER I</pre>
81+ * </p>
82+ *
83+ * or as the single character
84+ *
85+ * <p><pre>
86+ * U+FB03 LATIN SMALL LIGATURE FFI</pre>
87+ * </p>
88+ *
89+ * The ffi ligature is not a distinct semantic character, and strictly speaking
90+ * it shouldn't be in Unicode at all, but it was included for compatibility
91+ * with existing character sets that already provided it. The Unicode standard
92+ * identifies such characters by giving them "compatibility" decompositions
93+ * into the corresponding semantic characters. When sorting and searching, you
94+ * will often want to use these mappings.
95+ * <p>
96+ * The <code>normalize</code> method helps solve these problems by transforming
97+ * text into the canonical composed and decomposed forms as shown in the first
98+ * example above. In addition, you can have it perform compatibility
99+ * decompositions so that you can treat compatibility characters the same as
100+ * their equivalents.
101+ * Finally, the <code>normalize</code> method rearranges accents into the
102+ * proper canonical order, so that you do not have to worry about accent
103+ * rearrangement on your own.
104+ * <p>
105+ * The W3C generally recommends to exchange texts in NFC.
106+ * Note also that most legacy character encodings use only precomposed forms and
107+ * often do not encode any combining marks by themselves. For conversion to such
108+ * character encodings the Unicode text needs to be normalized to NFC.
109+ * For more usage examples, see the Unicode Standard Annex.
110+ *
111+ * @since 1.6
112+ */
113+public final class Normalizer {
114+
115+ private Normalizer() {};
116+
117+ /**
118+ * This enum provides constants of the four Unicode normalization forms
119+ * that are described in
120+ * <a href="http://www.unicode.org/unicode/reports/tr15/tr15-23.html">
121+ * Unicode Standard Annex #15 &mdash; Unicode Normalization Forms</a>
122+ * and two methods to access them.
123+ *
124+ * @since 1.6
125+ */
126+ public static enum Form {
127+
128+ /**
129+ * Canonical decomposition.
130+ */
131+ NFD,
132+
133+ /**
134+ * Canonical decomposition, followed by canonical composition.
135+ */
136+ NFC,
137+
138+ /**
139+ * Compatibility decomposition.
140+ */
141+ NFKD,
142+
143+ /**
144+ * Compatibility decomposition, followed by canonical composition.
145+ */
146+ NFKC
147+ }
148+
149+ /**
150+ * Normalize a sequence of char values.
151+ * The sequence will be normalized according to the specified normalization
152+ * from.
153+ * @param src The sequence of char values to normalize.
154+ * @param form The normalization form; one of
155+ * {@link java.text.Normalizer.Form#NFC},
156+ * {@link java.text.Normalizer.Form#NFD},
157+ * {@link java.text.Normalizer.Form#NFKC},
158+ * {@link java.text.Normalizer.Form#NFKD}
159+ * @return The normalized String
160+ * @throws NullPointerException If <code>src</code> or <code>form</code>
161+ * is null.
162+ */
163+ public static String normalize(CharSequence src, Form form) {
164+ return NormalizerBase.normalize(src.toString(), form);
165+ }
166+
167+ /**
168+ * Determines if the given sequence of char values is normalized.
169+ * @param src The sequence of char values to be checked.
170+ * @param form The normalization form; one of
171+ * {@link java.text.Normalizer.Form#NFC},
172+ * {@link java.text.Normalizer.Form#NFD},
173+ * {@link java.text.Normalizer.Form#NFKC},
174+ * {@link java.text.Normalizer.Form#NFKD}
175+ * @return true if the sequence of char values is normalized;
176+ * false otherwise.
177+ * @throws NullPointerException If <code>src</code> or <code>form</code>
178+ * is null.
179+ */
180+ public static boolean isNormalized(CharSequence src, Form form) {
181+ return NormalizerBase.isNormalized(src.toString(), form);
182+ }
183+}
java/pkg/java/text/NumberFormat$Field.class+0−0

Binary file not shown.

java/pkg/java/text/NumberFormat$NumberFormatGetter.class+0−0

Binary file not shown.

java/pkg/java/text/NumberFormat.class+0−0

Binary file not shown.

java/pkg/java/text/NumberFormat.java+1162−0
@@ -0,0 +1,1162 @@
1+/*
2+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.io.InvalidObjectException;
42+import java.io.IOException;
43+import java.io.ObjectInputStream;
44+import java.io.ObjectOutputStream;
45+import java.math.BigInteger;
46+import java.math.RoundingMode;
47+import java.text.spi.NumberFormatProvider;
48+import java.util.Currency;
49+import java.util.HashMap;
50+import java.util.Hashtable;
51+import java.util.Locale;
52+import java.util.Map;
53+import java.util.ResourceBundle;
54+import java.util.concurrent.atomic.AtomicInteger;
55+import java.util.concurrent.atomic.AtomicLong;
56+import java.util.spi.LocaleServiceProvider;
57+import sun.util.LocaleServiceProviderPool;
58+import sun.util.resources.LocaleData;
59+
60+/**
61+ * <code>NumberFormat</code> is the abstract base class for all number
62+ * formats. This class provides the interface for formatting and parsing
63+ * numbers. <code>NumberFormat</code> also provides methods for determining
64+ * which locales have number formats, and what their names are.
65+ *
66+ * <p>
67+ * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
68+ * Your code can be completely independent of the locale conventions for
69+ * decimal points, thousands-separators, or even the particular decimal
70+ * digits used, or whether the number format is even decimal.
71+ *
72+ * <p>
73+ * To format a number for the current Locale, use one of the factory
74+ * class methods:
75+ * <blockquote>
76+ * <pre>
77+ * myString = NumberFormat.getInstance().format(myNumber);
78+ * </pre>
79+ * </blockquote>
80+ * If you are formatting multiple numbers, it is
81+ * more efficient to get the format and use it multiple times so that
82+ * the system doesn't have to fetch the information about the local
83+ * language and country conventions multiple times.
84+ * <blockquote>
85+ * <pre>
86+ * NumberFormat nf = NumberFormat.getInstance();
87+ * for (int i = 0; i < myNumber.length; ++i) {
88+ * output.println(nf.format(myNumber[i]) + "; ");
89+ * }
90+ * </pre>
91+ * </blockquote>
92+ * To format a number for a different Locale, specify it in the
93+ * call to <code>getInstance</code>.
94+ * <blockquote>
95+ * <pre>
96+ * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
97+ * </pre>
98+ * </blockquote>
99+ * You can also use a <code>NumberFormat</code> to parse numbers:
100+ * <blockquote>
101+ * <pre>
102+ * myNumber = nf.parse(myString);
103+ * </pre>
104+ * </blockquote>
105+ * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
106+ * normal number format. Use <code>getIntegerInstance</code> to get an
107+ * integer number format. Use <code>getCurrencyInstance</code> to get the
108+ * currency number format. And use <code>getPercentInstance</code> to get a
109+ * format for displaying percentages. With this format, a fraction like
110+ * 0.53 is displayed as 53%.
111+ *
112+ * <p>
113+ * You can also control the display of numbers with such methods as
114+ * <code>setMinimumFractionDigits</code>.
115+ * If you want even more control over the format or parsing,
116+ * or want to give your users more control,
117+ * you can try casting the <code>NumberFormat</code> you get from the factory methods
118+ * to a <code>DecimalFormat</code>. This will work for the vast majority
119+ * of locales; just remember to put it in a <code>try</code> block in case you
120+ * encounter an unusual one.
121+ *
122+ * <p>
123+ * NumberFormat and DecimalFormat are designed such that some controls
124+ * work for formatting and others work for parsing. The following is
125+ * the detailed description for each these control methods,
126+ * <p>
127+ * setParseIntegerOnly : only affects parsing, e.g.
128+ * if true, "3456.78" -> 3456 (and leaves the parse position just after index 6)
129+ * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
130+ * This is independent of formatting. If you want to not show a decimal point
131+ * where there might be no digits after the decimal point, use
132+ * setDecimalSeparatorAlwaysShown.
133+ * <p>
134+ * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
135+ * there might be no digits after the decimal point, such as with a pattern
136+ * like "#,##0.##", e.g.,
137+ * if true, 3456.00 -> "3,456."
138+ * if false, 3456.00 -> "3456"
139+ * This is independent of parsing. If you want parsing to stop at the decimal
140+ * point, use setParseIntegerOnly.
141+ *
142+ * <p>
143+ * You can also use forms of the <code>parse</code> and <code>format</code>
144+ * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
145+ * allow you to:
146+ * <ul>
147+ * <li> progressively parse through pieces of a string
148+ * <li> align the decimal point and other areas
149+ * </ul>
150+ * For example, you can align numbers in two ways:
151+ * <ol>
152+ * <li> If you are using a monospaced font with spacing for alignment,
153+ * you can pass the <code>FieldPosition</code> in your format call, with
154+ * <code>field</code> = <code>INTEGER_FIELD</code>. On output,
155+ * <code>getEndIndex</code> will be set to the offset between the
156+ * last character of the integer and the decimal. Add
157+ * (desiredSpaceCount - getEndIndex) spaces at the front of the string.
158+ *
159+ * <li> If you are using proportional fonts,
160+ * instead of padding with spaces, measure the width
161+ * of the string in pixels from the start to <code>getEndIndex</code>.
162+ * Then move the pen by
163+ * (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
164+ * It also works where there is no decimal, but possibly additional
165+ * characters at the end, e.g., with parentheses in negative
166+ * numbers: "(12)" for -12.
167+ * </ol>
168+ *
169+ * <h4><a name="synchronization">Synchronization</a></h4>
170+ *
171+ * <p>
172+ * Number formats are generally not synchronized.
173+ * It is recommended to create separate format instances for each thread.
174+ * If multiple threads access a format concurrently, it must be synchronized
175+ * externally.
176+ *
177+ * @see DecimalFormat
178+ * @see ChoiceFormat
179+ * @author Mark Davis
180+ * @author Helena Shih
181+ */
182+public abstract class NumberFormat extends Format {
183+
184+ /**
185+ * Field constant used to construct a FieldPosition object. Signifies that
186+ * the position of the integer part of a formatted number should be returned.
187+ * @see java.text.FieldPosition
188+ */
189+ public static final int INTEGER_FIELD = 0;
190+
191+ /**
192+ * Field constant used to construct a FieldPosition object. Signifies that
193+ * the position of the fraction part of a formatted number should be returned.
194+ * @see java.text.FieldPosition
195+ */
196+ public static final int FRACTION_FIELD = 1;
197+
198+ /**
199+ * Sole constructor. (For invocation by subclass constructors, typically
200+ * implicit.)
201+ */
202+ protected NumberFormat() {
203+ }
204+
205+ /**
206+ * Formats a number and appends the resulting text to the given string
207+ * buffer.
208+ * The number can be of any subclass of {@link java.lang.Number}.
209+ * <p>
210+ * This implementation extracts the number's value using
211+ * {@link java.lang.Number#longValue()} for all integral type values that
212+ * can be converted to <code>long</code> without loss of information,
213+ * including <code>BigInteger</code> values with a
214+ * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
215+ * and {@link java.lang.Number#doubleValue()} for all other types. It
216+ * then calls
217+ * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
218+ * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
219+ * This may result in loss of magnitude information and precision for
220+ * <code>BigInteger</code> and <code>BigDecimal</code> values.
221+ * @param number the number to format
222+ * @param toAppendTo the <code>StringBuffer</code> to which the formatted
223+ * text is to be appended
224+ * @param pos On input: an alignment field, if desired.
225+ * On output: the offsets of the alignment field.
226+ * @return the value passed in as <code>toAppendTo</code>
227+ * @exception IllegalArgumentException if <code>number</code> is
228+ * null or not an instance of <code>Number</code>.
229+ * @exception NullPointerException if <code>toAppendTo</code> or
230+ * <code>pos</code> is null
231+ * @exception ArithmeticException if rounding is needed with rounding
232+ * mode being set to RoundingMode.UNNECESSARY
233+ * @see java.text.FieldPosition
234+ */
235+ public StringBuffer format(Object number,
236+ StringBuffer toAppendTo,
237+ FieldPosition pos) {
238+ if (number instanceof Long || number instanceof Integer ||
239+ number instanceof Short || number instanceof Byte ||
240+ number instanceof AtomicInteger || number instanceof AtomicLong ||
241+ (number instanceof BigInteger &&
242+ ((BigInteger)number).bitLength() < 64)) {
243+ return format(((Number)number).longValue(), toAppendTo, pos);
244+ } else if (number instanceof Number) {
245+ return format(((Number)number).doubleValue(), toAppendTo, pos);
246+ } else {
247+ throw new IllegalArgumentException("Cannot format given Object as a Number");
248+ }
249+ }
250+
251+ /**
252+ * Parses text from a string to produce a <code>Number</code>.
253+ * <p>
254+ * The method attempts to parse text starting at the index given by
255+ * <code>pos</code>.
256+ * If parsing succeeds, then the index of <code>pos</code> is updated
257+ * to the index after the last character used (parsing does not necessarily
258+ * use all characters up to the end of the string), and the parsed
259+ * number is returned. The updated <code>pos</code> can be used to
260+ * indicate the starting point for the next call to this method.
261+ * If an error occurs, then the index of <code>pos</code> is not
262+ * changed, the error index of <code>pos</code> is set to the index of
263+ * the character where the error occurred, and null is returned.
264+ * <p>
265+ * See the {@link #parse(String, ParsePosition)} method for more information
266+ * on number parsing.
267+ *
268+ * @param source A <code>String</code>, part of which should be parsed.
269+ * @param pos A <code>ParsePosition</code> object with index and error
270+ * index information as described above.
271+ * @return A <code>Number</code> parsed from the string. In case of
272+ * error, returns null.
273+ * @exception NullPointerException if <code>pos</code> is null.
274+ */
275+ public final Object parseObject(String source, ParsePosition pos) {
276+ return parse(source, pos);
277+ }
278+
279+ /**
280+ * Specialization of format.
281+ * @exception ArithmeticException if rounding is needed with rounding
282+ * mode being set to RoundingMode.UNNECESSARY
283+ * @see java.text.Format#format
284+ */
285+ public final String format(double number) {
286+ return format(number, new StringBuffer(),
287+ DontCareFieldPosition.INSTANCE).toString();
288+ }
289+
290+ /**
291+ * Specialization of format.
292+ * @exception ArithmeticException if rounding is needed with rounding
293+ * mode being set to RoundingMode.UNNECESSARY
294+ * @see java.text.Format#format
295+ */
296+ public final String format(long number) {
297+ return format(number, new StringBuffer(),
298+ DontCareFieldPosition.INSTANCE).toString();
299+ }
300+
301+ /**
302+ * Specialization of format.
303+ * @exception ArithmeticException if rounding is needed with rounding
304+ * mode being set to RoundingMode.UNNECESSARY
305+ * @see java.text.Format#format
306+ */
307+ public abstract StringBuffer format(double number,
308+ StringBuffer toAppendTo,
309+ FieldPosition pos);
310+
311+ /**
312+ * Specialization of format.
313+ * @exception ArithmeticException if rounding is needed with rounding
314+ * mode being set to RoundingMode.UNNECESSARY
315+ * @see java.text.Format#format
316+ */
317+ public abstract StringBuffer format(long number,
318+ StringBuffer toAppendTo,
319+ FieldPosition pos);
320+
321+ /**
322+ * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
323+ * Long.MAX_VALUE] and with no decimals), otherwise a Double.
324+ * If IntegerOnly is set, will stop at a decimal
325+ * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
326+ * after the 1).
327+ * Does not throw an exception; if no object can be parsed, index is
328+ * unchanged!
329+ * @see java.text.NumberFormat#isParseIntegerOnly
330+ * @see java.text.Format#parseObject
331+ */
332+ public abstract Number parse(String source, ParsePosition parsePosition);
333+
334+ /**
335+ * Parses text from the beginning of the given string to produce a number.
336+ * The method may not use the entire text of the given string.
337+ * <p>
338+ * See the {@link #parse(String, ParsePosition)} method for more information
339+ * on number parsing.
340+ *
341+ * @param source A <code>String</code> whose beginning should be parsed.
342+ * @return A <code>Number</code> parsed from the string.
343+ * @exception ParseException if the beginning of the specified string
344+ * cannot be parsed.
345+ */
346+ public Number parse(String source) throws ParseException {
347+ ParsePosition parsePosition = new ParsePosition(0);
348+ Number result = parse(source, parsePosition);
349+ if (parsePosition.index == 0) {
350+ throw new ParseException("Unparseable number: \"" + source + "\"",
351+ parsePosition.errorIndex);
352+ }
353+ return result;
354+ }
355+
356+ /**
357+ * Returns true if this format will parse numbers as integers only.
358+ * For example in the English locale, with ParseIntegerOnly true, the
359+ * string "1234." would be parsed as the integer value 1234 and parsing
360+ * would stop at the "." character. Of course, the exact format accepted
361+ * by the parse operation is locale dependant and determined by sub-classes
362+ * of NumberFormat.
363+ */
364+ public boolean isParseIntegerOnly() {
365+ return parseIntegerOnly;
366+ }
367+
368+ /**
369+ * Sets whether or not numbers should be parsed as integers only.
370+ * @see #isParseIntegerOnly
371+ */
372+ public void setParseIntegerOnly(boolean value) {
373+ parseIntegerOnly = value;
374+ }
375+
376+ //============== Locale Stuff =====================
377+
378+ /**
379+ * Returns a general-purpose number format for the current default locale.
380+ * This is the same as calling
381+ * {@link #getNumberInstance() getNumberInstance()}.
382+ */
383+ public final static NumberFormat getInstance() {
384+ return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
385+ }
386+
387+ /**
388+ * Returns a general-purpose number format for the specified locale.
389+ * This is the same as calling
390+ * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
391+ */
392+ public static NumberFormat getInstance(Locale inLocale) {
393+ return getInstance(inLocale, NUMBERSTYLE);
394+ }
395+
396+ /**
397+ * Returns a general-purpose number format for the current default locale.
398+ */
399+ public final static NumberFormat getNumberInstance() {
400+ return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
401+ }
402+
403+ /**
404+ * Returns a general-purpose number format for the specified locale.
405+ */
406+ public static NumberFormat getNumberInstance(Locale inLocale) {
407+ return getInstance(inLocale, NUMBERSTYLE);
408+ }
409+
410+ /**
411+ * Returns an integer number format for the current default locale. The
412+ * returned number format is configured to round floating point numbers
413+ * to the nearest integer using half-even rounding (see {@link
414+ * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
415+ * and to parse only the integer part of an input string (see {@link
416+ * #isParseIntegerOnly isParseIntegerOnly}).
417+ *
418+ * @see #getRoundingMode()
419+ * @return a number format for integer values
420+ * @since 1.4
421+ */
422+ public final static NumberFormat getIntegerInstance() {
423+ return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
424+ }
425+
426+ /**
427+ * Returns an integer number format for the specified locale. The
428+ * returned number format is configured to round floating point numbers
429+ * to the nearest integer using half-even rounding (see {@link
430+ * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
431+ * and to parse only the integer part of an input string (see {@link
432+ * #isParseIntegerOnly isParseIntegerOnly}).
433+ *
434+ * @see #getRoundingMode()
435+ * @return a number format for integer values
436+ * @since 1.4
437+ */
438+ public static NumberFormat getIntegerInstance(Locale inLocale) {
439+ return getInstance(inLocale, INTEGERSTYLE);
440+ }
441+
442+ /**
443+ * Returns a currency format for the current default locale.
444+ */
445+ public final static NumberFormat getCurrencyInstance() {
446+ return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
447+ }
448+
449+ /**
450+ * Returns a currency format for the specified locale.
451+ */
452+ public static NumberFormat getCurrencyInstance(Locale inLocale) {
453+ return getInstance(inLocale, CURRENCYSTYLE);
454+ }
455+
456+ /**
457+ * Returns a percentage format for the current default locale.
458+ */
459+ public final static NumberFormat getPercentInstance() {
460+ return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
461+ }
462+
463+ /**
464+ * Returns a percentage format for the specified locale.
465+ */
466+ public static NumberFormat getPercentInstance(Locale inLocale) {
467+ return getInstance(inLocale, PERCENTSTYLE);
468+ }
469+
470+ /**
471+ * Returns a scientific format for the current default locale.
472+ */
473+ /*public*/ final static NumberFormat getScientificInstance() {
474+ return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
475+ }
476+
477+ /**
478+ * Returns a scientific format for the specified locale.
479+ */
480+ /*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
481+ return getInstance(inLocale, SCIENTIFICSTYLE);
482+ }
483+
484+ /**
485+ * Returns an array of all locales for which the
486+ * <code>get*Instance</code> methods of this class can return
487+ * localized instances.
488+ * The returned array represents the union of locales supported by the Java
489+ * runtime and by installed
490+ * {@link java.text.spi.NumberFormatProvider NumberFormatProvider} implementations.
491+ * It must contain at least a <code>Locale</code> instance equal to
492+ * {@link java.util.Locale#US Locale.US}.
493+ *
494+ * @return An array of locales for which localized
495+ * <code>NumberFormat</code> instances are available.
496+ */
497+ public static Locale[] getAvailableLocales() {
498+ LocaleServiceProviderPool pool =
499+ LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
500+ return pool.getAvailableLocales();
501+ }
502+
503+ /**
504+ * Overrides hashCode
505+ */
506+ public int hashCode() {
507+ return maximumIntegerDigits * 37 + maxFractionDigits;
508+ // just enough fields for a reasonable distribution
509+ }
510+
511+ /**
512+ * Overrides equals
513+ */
514+ public boolean equals(Object obj) {
515+ if (obj == null) {
516+ return false;
517+ }
518+ if (this == obj) {
519+ return true;
520+ }
521+ if (getClass() != obj.getClass()) {
522+ return false;
523+ }
524+ NumberFormat other = (NumberFormat) obj;
525+ return (maximumIntegerDigits == other.maximumIntegerDigits
526+ && minimumIntegerDigits == other.minimumIntegerDigits
527+ && maximumFractionDigits == other.maximumFractionDigits
528+ && minimumFractionDigits == other.minimumFractionDigits
529+ && groupingUsed == other.groupingUsed
530+ && parseIntegerOnly == other.parseIntegerOnly);
531+ }
532+
533+ /**
534+ * Overrides Cloneable
535+ */
536+ public Object clone() {
537+ NumberFormat other = (NumberFormat) super.clone();
538+ return other;
539+ }
540+
541+ /**
542+ * Returns true if grouping is used in this format. For example, in the
543+ * English locale, with grouping on, the number 1234567 might be formatted
544+ * as "1,234,567". The grouping separator as well as the size of each group
545+ * is locale dependant and is determined by sub-classes of NumberFormat.
546+ * @see #setGroupingUsed
547+ */
548+ public boolean isGroupingUsed() {
549+ return groupingUsed;
550+ }
551+
552+ /**
553+ * Set whether or not grouping will be used in this format.
554+ * @see #isGroupingUsed
555+ */
556+ public void setGroupingUsed(boolean newValue) {
557+ groupingUsed = newValue;
558+ }
559+
560+ /**
561+ * Returns the maximum number of digits allowed in the integer portion of a
562+ * number.
563+ * @see #setMaximumIntegerDigits
564+ */
565+ public int getMaximumIntegerDigits() {
566+ return maximumIntegerDigits;
567+ }
568+
569+ /**
570+ * Sets the maximum number of digits allowed in the integer portion of a
571+ * number. maximumIntegerDigits must be >= minimumIntegerDigits. If the
572+ * new value for maximumIntegerDigits is less than the current value
573+ * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
574+ * the new value.
575+ * @param newValue the maximum number of integer digits to be shown; if
576+ * less than zero, then zero is used. The concrete subclass may enforce an
577+ * upper limit to this value appropriate to the numeric type being formatted.
578+ * @see #getMaximumIntegerDigits
579+ */
580+ public void setMaximumIntegerDigits(int newValue) {
581+ maximumIntegerDigits = Math.max(0,newValue);
582+ if (minimumIntegerDigits > maximumIntegerDigits) {
583+ minimumIntegerDigits = maximumIntegerDigits;
584+ }
585+ }
586+
587+ /**
588+ * Returns the minimum number of digits allowed in the integer portion of a
589+ * number.
590+ * @see #setMinimumIntegerDigits
591+ */
592+ public int getMinimumIntegerDigits() {
593+ return minimumIntegerDigits;
594+ }
595+
596+ /**
597+ * Sets the minimum number of digits allowed in the integer portion of a
598+ * number. minimumIntegerDigits must be <= maximumIntegerDigits. If the
599+ * new value for minimumIntegerDigits exceeds the current value
600+ * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
601+ * the new value
602+ * @param newValue the minimum number of integer digits to be shown; if
603+ * less than zero, then zero is used. The concrete subclass may enforce an
604+ * upper limit to this value appropriate to the numeric type being formatted.
605+ * @see #getMinimumIntegerDigits
606+ */
607+ public void setMinimumIntegerDigits(int newValue) {
608+ minimumIntegerDigits = Math.max(0,newValue);
609+ if (minimumIntegerDigits > maximumIntegerDigits) {
610+ maximumIntegerDigits = minimumIntegerDigits;
611+ }
612+ }
613+
614+ /**
615+ * Returns the maximum number of digits allowed in the fraction portion of a
616+ * number.
617+ * @see #setMaximumFractionDigits
618+ */
619+ public int getMaximumFractionDigits() {
620+ return maximumFractionDigits;
621+ }
622+
623+ /**
624+ * Sets the maximum number of digits allowed in the fraction portion of a
625+ * number. maximumFractionDigits must be >= minimumFractionDigits. If the
626+ * new value for maximumFractionDigits is less than the current value
627+ * of minimumFractionDigits, then minimumFractionDigits will also be set to
628+ * the new value.
629+ * @param newValue the maximum number of fraction digits to be shown; if
630+ * less than zero, then zero is used. The concrete subclass may enforce an
631+ * upper limit to this value appropriate to the numeric type being formatted.
632+ * @see #getMaximumFractionDigits
633+ */
634+ public void setMaximumFractionDigits(int newValue) {
635+ maximumFractionDigits = Math.max(0,newValue);
636+ if (maximumFractionDigits < minimumFractionDigits) {
637+ minimumFractionDigits = maximumFractionDigits;
638+ }
639+ }
640+
641+ /**
642+ * Returns the minimum number of digits allowed in the fraction portion of a
643+ * number.
644+ * @see #setMinimumFractionDigits
645+ */
646+ public int getMinimumFractionDigits() {
647+ return minimumFractionDigits;
648+ }
649+
650+ /**
651+ * Sets the minimum number of digits allowed in the fraction portion of a
652+ * number. minimumFractionDigits must be <= maximumFractionDigits. If the
653+ * new value for minimumFractionDigits exceeds the current value
654+ * of maximumFractionDigits, then maximumIntegerDigits will also be set to
655+ * the new value
656+ * @param newValue the minimum number of fraction digits to be shown; if
657+ * less than zero, then zero is used. The concrete subclass may enforce an
658+ * upper limit to this value appropriate to the numeric type being formatted.
659+ * @see #getMinimumFractionDigits
660+ */
661+ public void setMinimumFractionDigits(int newValue) {
662+ minimumFractionDigits = Math.max(0,newValue);
663+ if (maximumFractionDigits < minimumFractionDigits) {
664+ maximumFractionDigits = minimumFractionDigits;
665+ }
666+ }
667+
668+ /**
669+ * Gets the currency used by this number format when formatting
670+ * currency values. The initial value is derived in a locale dependent
671+ * way. The returned value may be null if no valid
672+ * currency could be determined and no currency has been set using
673+ * {@link #setCurrency(java.util.Currency) setCurrency}.
674+ * <p>
675+ * The default implementation throws
676+ * <code>UnsupportedOperationException</code>.
677+ *
678+ * @return the currency used by this number format, or <code>null</code>
679+ * @exception UnsupportedOperationException if the number format class
680+ * doesn't implement currency formatting
681+ * @since 1.4
682+ */
683+ public Currency getCurrency() {
684+ throw new UnsupportedOperationException();
685+ }
686+
687+ /**
688+ * Sets the currency used by this number format when formatting
689+ * currency values. This does not update the minimum or maximum
690+ * number of fraction digits used by the number format.
691+ * <p>
692+ * The default implementation throws
693+ * <code>UnsupportedOperationException</code>.
694+ *
695+ * @param currency the new currency to be used by this number format
696+ * @exception UnsupportedOperationException if the number format class
697+ * doesn't implement currency formatting
698+ * @exception NullPointerException if <code>currency</code> is null
699+ * @since 1.4
700+ */
701+ public void setCurrency(Currency currency) {
702+ throw new UnsupportedOperationException();
703+ }
704+
705+ /**
706+ * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
707+ * The default implementation of this method in NumberFormat
708+ * always throws {@link java.lang.UnsupportedOperationException}.
709+ * Subclasses which handle different rounding modes should override
710+ * this method.
711+ *
712+ * @exception UnsupportedOperationException The default implementation
713+ * always throws this exception
714+ * @return The <code>RoundingMode</code> used for this NumberFormat.
715+ * @see #setRoundingMode(RoundingMode)
716+ * @since 1.6
717+ */
718+ public RoundingMode getRoundingMode() {
719+ throw new UnsupportedOperationException();
720+ }
721+
722+ /**
723+ * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
724+ * The default implementation of this method in NumberFormat always
725+ * throws {@link java.lang.UnsupportedOperationException}.
726+ * Subclasses which handle different rounding modes should override
727+ * this method.
728+ *
729+ * @exception UnsupportedOperationException The default implementation
730+ * always throws this exception
731+ * @exception NullPointerException if <code>roundingMode</code> is null
732+ * @param roundingMode The <code>RoundingMode</code> to be used
733+ * @see #getRoundingMode()
734+ * @since 1.6
735+ */
736+ public void setRoundingMode(RoundingMode roundingMode) {
737+ throw new UnsupportedOperationException();
738+ }
739+
740+ // =======================privates===============================
741+
742+ private static NumberFormat getInstance(Locale desiredLocale,
743+ int choice) {
744+ // Check whether a provider can provide an implementation that's closer
745+ // to the requested locale than what the Java runtime itself can provide.
746+ LocaleServiceProviderPool pool =
747+ LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
748+ if (pool.hasProviders()) {
749+ NumberFormat providersInstance = pool.getLocalizedObject(
750+ NumberFormatGetter.INSTANCE,
751+ desiredLocale,
752+ choice);
753+ if (providersInstance != null) {
754+ return providersInstance;
755+ }
756+ }
757+
758+ /* try the cache first */
759+ String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
760+ if (numberPatterns == null) { /* cache miss */
761+ ResourceBundle resource = LocaleData.getNumberFormatData(desiredLocale);
762+ numberPatterns = resource.getStringArray("NumberPatterns");
763+ /* update cache */
764+ cachedLocaleData.put(desiredLocale, numberPatterns);
765+ }
766+
767+ DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
768+ int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
769+ DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
770+
771+ if (choice == INTEGERSTYLE) {
772+ format.setMaximumFractionDigits(0);
773+ format.setDecimalSeparatorAlwaysShown(false);
774+ format.setParseIntegerOnly(true);
775+ } else if (choice == CURRENCYSTYLE) {
776+ format.adjustForCurrencyDefaultFractionDigits();
777+ }
778+
779+ return format;
780+ }
781+
782+ /**
783+ * First, read in the default serializable data.
784+ *
785+ * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
786+ * the stream was written by JDK 1.1,
787+ * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
788+ * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
789+ * since the <code>int</code> fields were not present in JDK 1.1.
790+ * Finally, set serialVersionOnStream back to the maximum allowed value so that
791+ * default serialization will work properly if this object is streamed out again.
792+ *
793+ * <p>If <code>minimumIntegerDigits</code> is greater than
794+ * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
795+ * is greater than <code>maximumFractionDigits</code>, then the stream data
796+ * is invalid and this method throws an <code>InvalidObjectException</code>.
797+ * In addition, if any of these values is negative, then this method throws
798+ * an <code>InvalidObjectException</code>.
799+ *
800+ * @since 1.2
801+ */
802+ private void readObject(ObjectInputStream stream)
803+ throws IOException, ClassNotFoundException
804+ {
805+ stream.defaultReadObject();
806+ if (serialVersionOnStream < 1) {
807+ // Didn't have additional int fields, reassign to use them.
808+ maximumIntegerDigits = maxIntegerDigits;
809+ minimumIntegerDigits = minIntegerDigits;
810+ maximumFractionDigits = maxFractionDigits;
811+ minimumFractionDigits = minFractionDigits;
812+ }
813+ if (minimumIntegerDigits > maximumIntegerDigits ||
814+ minimumFractionDigits > maximumFractionDigits ||
815+ minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
816+ throw new InvalidObjectException("Digit count range invalid");
817+ }
818+ serialVersionOnStream = currentSerialVersion;
819+ }
820+
821+ /**
822+ * Write out the default serializable data, after first setting
823+ * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
824+ * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
825+ * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
826+ * with the JDK 1.1 version of the stream format.
827+ *
828+ * @since 1.2
829+ */
830+ private void writeObject(ObjectOutputStream stream)
831+ throws IOException
832+ {
833+ maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
834+ Byte.MAX_VALUE : (byte)maximumIntegerDigits;
835+ minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
836+ Byte.MAX_VALUE : (byte)minimumIntegerDigits;
837+ maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
838+ Byte.MAX_VALUE : (byte)maximumFractionDigits;
839+ minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
840+ Byte.MAX_VALUE : (byte)minimumFractionDigits;
841+ stream.defaultWriteObject();
842+ }
843+
844+ /**
845+ * Cache to hold the NumberPatterns of a Locale.
846+ */
847+ private static final Hashtable cachedLocaleData = new Hashtable(3);
848+
849+ // Constants used by factory methods to specify a style of format.
850+ private static final int NUMBERSTYLE = 0;
851+ private static final int CURRENCYSTYLE = 1;
852+ private static final int PERCENTSTYLE = 2;
853+ private static final int SCIENTIFICSTYLE = 3;
854+ private static final int INTEGERSTYLE = 4;
855+
856+ /**
857+ * True if the grouping (i.e. thousands) separator is used when
858+ * formatting and parsing numbers.
859+ *
860+ * @serial
861+ * @see #isGroupingUsed
862+ */
863+ private boolean groupingUsed = true;
864+
865+ /**
866+ * The maximum number of digits allowed in the integer portion of a
867+ * number. <code>maxIntegerDigits</code> must be greater than or equal to
868+ * <code>minIntegerDigits</code>.
869+ * <p>
870+ * <strong>Note:</strong> This field exists only for serialization
871+ * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
872+ * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
873+ * When writing to a stream, <code>maxIntegerDigits</code> is set to
874+ * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
875+ * whichever is smaller. When reading from a stream, this field is used
876+ * only if <code>serialVersionOnStream</code> is less than 1.
877+ *
878+ * @serial
879+ * @see #getMaximumIntegerDigits
880+ */
881+ private byte maxIntegerDigits = 40;
882+
883+ /**
884+ * The minimum number of digits allowed in the integer portion of a
885+ * number. <code>minimumIntegerDigits</code> must be less than or equal to
886+ * <code>maximumIntegerDigits</code>.
887+ * <p>
888+ * <strong>Note:</strong> This field exists only for serialization
889+ * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
890+ * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
891+ * When writing to a stream, <code>minIntegerDigits</code> is set to
892+ * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
893+ * whichever is smaller. When reading from a stream, this field is used
894+ * only if <code>serialVersionOnStream</code> is less than 1.
895+ *
896+ * @serial
897+ * @see #getMinimumIntegerDigits
898+ */
899+ private byte minIntegerDigits = 1;
900+
901+ /**
902+ * The maximum number of digits allowed in the fractional portion of a
903+ * number. <code>maximumFractionDigits</code> must be greater than or equal to
904+ * <code>minimumFractionDigits</code>.
905+ * <p>
906+ * <strong>Note:</strong> This field exists only for serialization
907+ * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
908+ * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
909+ * When writing to a stream, <code>maxFractionDigits</code> is set to
910+ * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
911+ * whichever is smaller. When reading from a stream, this field is used
912+ * only if <code>serialVersionOnStream</code> is less than 1.
913+ *
914+ * @serial
915+ * @see #getMaximumFractionDigits
916+ */
917+ private byte maxFractionDigits = 3; // invariant, >= minFractionDigits
918+
919+ /**
920+ * The minimum number of digits allowed in the fractional portion of a
921+ * number. <code>minimumFractionDigits</code> must be less than or equal to
922+ * <code>maximumFractionDigits</code>.
923+ * <p>
924+ * <strong>Note:</strong> This field exists only for serialization
925+ * compatibility with JDK 1.1. In Java platform 2 v1.2 and higher, the new
926+ * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
927+ * When writing to a stream, <code>minFractionDigits</code> is set to
928+ * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
929+ * whichever is smaller. When reading from a stream, this field is used
930+ * only if <code>serialVersionOnStream</code> is less than 1.
931+ *
932+ * @serial
933+ * @see #getMinimumFractionDigits
934+ */
935+ private byte minFractionDigits = 0;
936+
937+ /**
938+ * True if this format will parse numbers as integers only.
939+ *
940+ * @serial
941+ * @see #isParseIntegerOnly
942+ */
943+ private boolean parseIntegerOnly = false;
944+
945+ // new fields for 1.2. byte is too small for integer digits.
946+
947+ /**
948+ * The maximum number of digits allowed in the integer portion of a
949+ * number. <code>maximumIntegerDigits</code> must be greater than or equal to
950+ * <code>minimumIntegerDigits</code>.
951+ *
952+ * @serial
953+ * @since 1.2
954+ * @see #getMaximumIntegerDigits
955+ */
956+ private int maximumIntegerDigits = 40;
957+
958+ /**
959+ * The minimum number of digits allowed in the integer portion of a
960+ * number. <code>minimumIntegerDigits</code> must be less than or equal to
961+ * <code>maximumIntegerDigits</code>.
962+ *
963+ * @serial
964+ * @since 1.2
965+ * @see #getMinimumIntegerDigits
966+ */
967+ private int minimumIntegerDigits = 1;
968+
969+ /**
970+ * The maximum number of digits allowed in the fractional portion of a
971+ * number. <code>maximumFractionDigits</code> must be greater than or equal to
972+ * <code>minimumFractionDigits</code>.
973+ *
974+ * @serial
975+ * @since 1.2
976+ * @see #getMaximumFractionDigits
977+ */
978+ private int maximumFractionDigits = 3; // invariant, >= minFractionDigits
979+
980+ /**
981+ * The minimum number of digits allowed in the fractional portion of a
982+ * number. <code>minimumFractionDigits</code> must be less than or equal to
983+ * <code>maximumFractionDigits</code>.
984+ *
985+ * @serial
986+ * @since 1.2
987+ * @see #getMinimumFractionDigits
988+ */
989+ private int minimumFractionDigits = 0;
990+
991+ static final int currentSerialVersion = 1;
992+
993+ /**
994+ * Describes the version of <code>NumberFormat</code> present on the stream.
995+ * Possible values are:
996+ * <ul>
997+ * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
998+ * In this version, the <code>int</code> fields such as
999+ * <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
1000+ * fields such as <code>maxIntegerDigits</code> are used instead.
1001+ *
1002+ * <li><b>1</b>: the 1.2 version of the stream format. The values of the
1003+ * <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
1004+ * and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
1005+ * are used instead.
1006+ * </ul>
1007+ * When streaming out a <code>NumberFormat</code>, the most recent format
1008+ * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
1009+ * is always written.
1010+ *
1011+ * @serial
1012+ * @since 1.2
1013+ */
1014+ private int serialVersionOnStream = currentSerialVersion;
1015+
1016+ // Removed "implements Cloneable" clause. Needs to update serialization
1017+ // ID for backward compatibility.
1018+ static final long serialVersionUID = -2308460125733713944L;
1019+
1020+
1021+ //
1022+ // class for AttributedCharacterIterator attributes
1023+ //
1024+ /**
1025+ * Defines constants that are used as attribute keys in the
1026+ * <code>AttributedCharacterIterator</code> returned
1027+ * from <code>NumberFormat.formatToCharacterIterator</code> and as
1028+ * field identifiers in <code>FieldPosition</code>.
1029+ *
1030+ * @since 1.4
1031+ */
1032+ public static class Field extends Format.Field {
1033+
1034+ // Proclaim serial compatibility with 1.4 FCS
1035+ private static final long serialVersionUID = 7494728892700160890L;
1036+
1037+ // table of all instances in this class, used by readResolve
1038+ private static final Map instanceMap = new HashMap(11);
1039+
1040+ /**
1041+ * Creates a Field instance with the specified
1042+ * name.
1043+ *
1044+ * @param name Name of the attribute
1045+ */
1046+ protected Field(String name) {
1047+ super(name);
1048+ if (this.getClass() == NumberFormat.Field.class) {
1049+ instanceMap.put(name, this);
1050+ }
1051+ }
1052+
1053+ /**
1054+ * Resolves instances being deserialized to the predefined constants.
1055+ *
1056+ * @throws InvalidObjectException if the constant could not be resolved.
1057+ * @return resolved NumberFormat.Field constant
1058+ */
1059+ protected Object readResolve() throws InvalidObjectException {
1060+ if (this.getClass() != NumberFormat.Field.class) {
1061+ throw new InvalidObjectException("subclass didn't correctly implement readResolve");
1062+ }
1063+
1064+ Object instance = instanceMap.get(getName());
1065+ if (instance != null) {
1066+ return instance;
1067+ } else {
1068+ throw new InvalidObjectException("unknown attribute name");
1069+ }
1070+ }
1071+
1072+ /**
1073+ * Constant identifying the integer field.
1074+ */
1075+ public static final Field INTEGER = new Field("integer");
1076+
1077+ /**
1078+ * Constant identifying the fraction field.
1079+ */
1080+ public static final Field FRACTION = new Field("fraction");
1081+
1082+ /**
1083+ * Constant identifying the exponent field.
1084+ */
1085+ public static final Field EXPONENT = new Field("exponent");
1086+
1087+ /**
1088+ * Constant identifying the decimal separator field.
1089+ */
1090+ public static final Field DECIMAL_SEPARATOR =
1091+ new Field("decimal separator");
1092+
1093+ /**
1094+ * Constant identifying the sign field.
1095+ */
1096+ public static final Field SIGN = new Field("sign");
1097+
1098+ /**
1099+ * Constant identifying the grouping separator field.
1100+ */
1101+ public static final Field GROUPING_SEPARATOR =
1102+ new Field("grouping separator");
1103+
1104+ /**
1105+ * Constant identifying the exponent symbol field.
1106+ */
1107+ public static final Field EXPONENT_SYMBOL = new
1108+ Field("exponent symbol");
1109+
1110+ /**
1111+ * Constant identifying the percent field.
1112+ */
1113+ public static final Field PERCENT = new Field("percent");
1114+
1115+ /**
1116+ * Constant identifying the permille field.
1117+ */
1118+ public static final Field PERMILLE = new Field("per mille");
1119+
1120+ /**
1121+ * Constant identifying the currency field.
1122+ */
1123+ public static final Field CURRENCY = new Field("currency");
1124+
1125+ /**
1126+ * Constant identifying the exponent sign field.
1127+ */
1128+ public static final Field EXPONENT_SIGN = new Field("exponent sign");
1129+ }
1130+
1131+ /**
1132+ * Obtains a NumberFormat instance from a NumberFormatProvider implementation.
1133+ */
1134+ private static class NumberFormatGetter
1135+ implements LocaleServiceProviderPool.LocalizedObjectGetter<NumberFormatProvider,
1136+ NumberFormat> {
1137+ private static final NumberFormatGetter INSTANCE = new NumberFormatGetter();
1138+
1139+ public NumberFormat getObject(NumberFormatProvider numberFormatProvider,
1140+ Locale locale,
1141+ String key,
1142+ Object... params) {
1143+ assert params.length == 1;
1144+ int choice = (Integer)params[0];
1145+
1146+ switch (choice) {
1147+ case NUMBERSTYLE:
1148+ return numberFormatProvider.getNumberInstance(locale);
1149+ case PERCENTSTYLE:
1150+ return numberFormatProvider.getPercentInstance(locale);
1151+ case CURRENCYSTYLE:
1152+ return numberFormatProvider.getCurrencyInstance(locale);
1153+ case INTEGERSTYLE:
1154+ return numberFormatProvider.getIntegerInstance(locale);
1155+ default:
1156+ assert false : choice;
1157+ }
1158+
1159+ return null;
1160+ }
1161+ }
1162+}
java/pkg/java/text/ParseException.class+0−0

Binary file not shown.

java/pkg/java/text/ParseException.java+78−0
@@ -0,0 +1,78 @@
1+/*
2+ * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+/**
42+ * Signals that an error has been reached unexpectedly
43+ * while parsing.
44+ * @see java.lang.Exception
45+ * @see java.text.Format
46+ * @see java.text.FieldPosition
47+ * @author Mark Davis
48+ */
49+public
50+class ParseException extends Exception {
51+
52+ /**
53+ * Constructs a ParseException with the specified detail message and
54+ * offset.
55+ * A detail message is a String that describes this particular exception.
56+ * @param s the detail message
57+ * @param errorOffset the position where the error is found while parsing.
58+ */
59+ public ParseException(String s, int errorOffset) {
60+ super(s);
61+ this.errorOffset = errorOffset;
62+ }
63+
64+ /**
65+ * Returns the position where the error was found.
66+ */
67+ public int getErrorOffset () {
68+ return errorOffset;
69+ }
70+
71+ //============ privates ============
72+ /**
73+ * The zero-based character offset into the string being parsed at which
74+ * the error was found during parsing.
75+ * @serial
76+ */
77+ private int errorOffset;
78+}
java/pkg/java/text/ParsePosition.class+0−0

Binary file not shown.

java/pkg/java/text/ParsePosition.java+139−0
@@ -0,0 +1,139 @@
1+/*
2+ * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+
42+/**
43+ * <code>ParsePosition</code> is a simple class used by <code>Format</code>
44+ * and its subclasses to keep track of the current position during parsing.
45+ * The <code>parseObject</code> method in the various <code>Format</code>
46+ * classes requires a <code>ParsePosition</code> object as an argument.
47+ *
48+ * <p>
49+ * By design, as you parse through a string with different formats,
50+ * you can use the same <code>ParsePosition</code>, since the index parameter
51+ * records the current position.
52+ *
53+ * @author Mark Davis
54+ * @see java.text.Format
55+ */
56+
57+public class ParsePosition {
58+
59+ /**
60+ * Input: the place you start parsing.
61+ * <br>Output: position where the parse stopped.
62+ * This is designed to be used serially,
63+ * with each call setting index up for the next one.
64+ */
65+ int index = 0;
66+ int errorIndex = -1;
67+
68+ /**
69+ * Retrieve the current parse position. On input to a parse method, this
70+ * is the index of the character at which parsing will begin; on output, it
71+ * is the index of the character following the last character parsed.
72+ */
73+ public int getIndex() {
74+ return index;
75+ }
76+
77+ /**
78+ * Set the current parse position.
79+ */
80+ public void setIndex(int index) {
81+ this.index = index;
82+ }
83+
84+ /**
85+ * Create a new ParsePosition with the given initial index.
86+ */
87+ public ParsePosition(int index) {
88+ this.index = index;
89+ }
90+ /**
91+ * Set the index at which a parse error occurred. Formatters
92+ * should set this before returning an error code from their
93+ * parseObject method. The default value is -1 if this is not set.
94+ * @since 1.2
95+ */
96+ public void setErrorIndex(int ei)
97+ {
98+ errorIndex = ei;
99+ }
100+
101+ /**
102+ * Retrieve the index at which an error occurred, or -1 if the
103+ * error index has not been set.
104+ * @since 1.2
105+ */
106+ public int getErrorIndex()
107+ {
108+ return errorIndex;
109+ }
110+ /**
111+ * Overrides equals
112+ */
113+ public boolean equals(Object obj)
114+ {
115+ if (obj == null) return false;
116+ if (!(obj instanceof ParsePosition))
117+ return false;
118+ ParsePosition other = (ParsePosition) obj;
119+ return (index == other.index && errorIndex == other.errorIndex);
120+ }
121+
122+ /**
123+ * Returns a hash code for this ParsePosition.
124+ * @return a hash code value for this object
125+ */
126+ public int hashCode() {
127+ return (errorIndex << 16) | index;
128+ }
129+
130+ /**
131+ * Return a string representation of this ParsePosition.
132+ * @return a string representation of this object
133+ */
134+ public String toString() {
135+ return getClass().getName() +
136+ "[index=" + index +
137+ ",errorIndex=" + errorIndex + ']';
138+ }
139+}
java/pkg/java/text/PatternEntry$Parser.class+0−0

Binary file not shown.

java/pkg/java/text/PatternEntry.class+0−0

Binary file not shown.

java/pkg/java/text/PatternEntry.java+306−0
@@ -0,0 +1,306 @@
1+/*
2+ * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996, 1997 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.lang.Character;
42+
43+/**
44+ * Utility class for normalizing and merging patterns for collation.
45+ * This is to be used with MergeCollation for adding patterns to an
46+ * existing rule table.
47+ * @see MergeCollation
48+ * @author Mark Davis, Helena Shih
49+ */
50+
51+class PatternEntry {
52+ /**
53+ * Gets the current extension, quoted
54+ */
55+ public void appendQuotedExtension(StringBuffer toAddTo) {
56+ appendQuoted(extension,toAddTo);
57+ }
58+
59+ /**
60+ * Gets the current chars, quoted
61+ */
62+ public void appendQuotedChars(StringBuffer toAddTo) {
63+ appendQuoted(chars,toAddTo);
64+ }
65+
66+ /**
67+ * WARNING this is used for searching in a Vector.
68+ * Because Vector.indexOf doesn't take a comparator,
69+ * this method is ill-defined and ignores strength.
70+ */
71+ public boolean equals(Object obj) {
72+ if (obj == null) return false;
73+ PatternEntry other = (PatternEntry) obj;
74+ boolean result = chars.equals(other.chars);
75+ return result;
76+ }
77+
78+ public int hashCode() {
79+ return chars.hashCode();
80+ }
81+
82+ /**
83+ * For debugging.
84+ */
85+ public String toString() {
86+ StringBuffer result = new StringBuffer();
87+ addToBuffer(result, true, false, null);
88+ return result.toString();
89+ }
90+
91+ /**
92+ * Gets the strength of the entry.
93+ */
94+ final int getStrength() {
95+ return strength;
96+ }
97+
98+ /**
99+ * Gets the expanding characters of the entry.
100+ */
101+ final String getExtension() {
102+ return extension;
103+ }
104+
105+ /**
106+ * Gets the core characters of the entry.
107+ */
108+ final String getChars() {
109+ return chars;
110+ }
111+
112+ // ===== privates =====
113+
114+ void addToBuffer(StringBuffer toAddTo,
115+ boolean showExtension,
116+ boolean showWhiteSpace,
117+ PatternEntry lastEntry)
118+ {
119+ if (showWhiteSpace && toAddTo.length() > 0)
120+ if (strength == Collator.PRIMARY || lastEntry != null)
121+ toAddTo.append('\n');
122+ else
123+ toAddTo.append(' ');
124+ if (lastEntry != null) {
125+ toAddTo.append('&');
126+ if (showWhiteSpace)
127+ toAddTo.append(' ');
128+ lastEntry.appendQuotedChars(toAddTo);
129+ appendQuotedExtension(toAddTo);
130+ if (showWhiteSpace)
131+ toAddTo.append(' ');
132+ }
133+ switch (strength) {
134+ case Collator.IDENTICAL: toAddTo.append('='); break;
135+ case Collator.TERTIARY: toAddTo.append(','); break;
136+ case Collator.SECONDARY: toAddTo.append(';'); break;
137+ case Collator.PRIMARY: toAddTo.append('<'); break;
138+ case RESET: toAddTo.append('&'); break;
139+ case UNSET: toAddTo.append('?'); break;
140+ }
141+ if (showWhiteSpace)
142+ toAddTo.append(' ');
143+ appendQuoted(chars,toAddTo);
144+ if (showExtension && extension.length() != 0) {
145+ toAddTo.append('/');
146+ appendQuoted(extension,toAddTo);
147+ }
148+ }
149+
150+ static void appendQuoted(String chars, StringBuffer toAddTo) {
151+ boolean inQuote = false;
152+ char ch = chars.charAt(0);
153+ if (Character.isSpaceChar(ch)) {
154+ inQuote = true;
155+ toAddTo.append('\'');
156+ } else {
157+ if (PatternEntry.isSpecialChar(ch)) {
158+ inQuote = true;
159+ toAddTo.append('\'');
160+ } else {
161+ switch (ch) {
162+ case 0x0010: case '\f': case '\r':
163+ case '\t': case '\n': case '@':
164+ inQuote = true;
165+ toAddTo.append('\'');
166+ break;
167+ case '\'':
168+ inQuote = true;
169+ toAddTo.append('\'');
170+ break;
171+ default:
172+ if (inQuote) {
173+ inQuote = false; toAddTo.append('\'');
174+ }
175+ break;
176+ }
177+ }
178+ }
179+ toAddTo.append(chars);
180+ if (inQuote)
181+ toAddTo.append('\'');
182+ }
183+
184+ //========================================================================
185+ // Parsing a pattern into a list of PatternEntries....
186+ //========================================================================
187+
188+ PatternEntry(int strength,
189+ StringBuffer chars,
190+ StringBuffer extension)
191+ {
192+ this.strength = strength;
193+ this.chars = chars.toString();
194+ this.extension = (extension.length() > 0) ? extension.toString()
195+ : "";
196+ }
197+
198+ static class Parser {
199+ private String pattern;
200+ private int i;
201+
202+ public Parser(String pattern) {
203+ this.pattern = pattern;
204+ this.i = 0;
205+ }
206+
207+ public PatternEntry next() throws ParseException {
208+ int newStrength = UNSET;
209+
210+ newChars.setLength(0);
211+ newExtension.setLength(0);
212+
213+ boolean inChars = true;
214+ boolean inQuote = false;
215+ mainLoop:
216+ while (i < pattern.length()) {
217+ char ch = pattern.charAt(i);
218+ if (inQuote) {
219+ if (ch == '\'') {
220+ inQuote = false;
221+ } else {
222+ if (newChars.length() == 0) newChars.append(ch);
223+ else if (inChars) newChars.append(ch);
224+ else newExtension.append(ch);
225+ }
226+ } else switch (ch) {
227+ case '=': if (newStrength != UNSET) break mainLoop;
228+ newStrength = Collator.IDENTICAL; break;
229+ case ',': if (newStrength != UNSET) break mainLoop;
230+ newStrength = Collator.TERTIARY; break;
231+ case ';': if (newStrength != UNSET) break mainLoop;
232+ newStrength = Collator.SECONDARY; break;
233+ case '<': if (newStrength != UNSET) break mainLoop;
234+ newStrength = Collator.PRIMARY; break;
235+ case '&': if (newStrength != UNSET) break mainLoop;
236+ newStrength = RESET; break;
237+ case '\t':
238+ case '\n':
239+ case '\f':
240+ case '\r':
241+ case ' ': break; // skip whitespace TODO use Character
242+ case '/': inChars = false; break;
243+ case '\'':
244+ inQuote = true;
245+ ch = pattern.charAt(++i);
246+ if (newChars.length() == 0) newChars.append(ch);
247+ else if (inChars) newChars.append(ch);
248+ else newExtension.append(ch);
249+ break;
250+ default:
251+ if (newStrength == UNSET) {
252+ throw new ParseException
253+ ("missing char (=,;<&) : " +
254+ pattern.substring(i,
255+ (i+10 < pattern.length()) ?
256+ i+10 : pattern.length()),
257+ i);
258+ }
259+ if (PatternEntry.isSpecialChar(ch) && (inQuote == false))
260+ throw new ParseException
261+ ("Unquoted punctuation character : " + Integer.toString(ch, 16), i);
262+ if (inChars) {
263+ newChars.append(ch);
264+ } else {
265+ newExtension.append(ch);
266+ }
267+ break;
268+ }
269+ i++;
270+ }
271+ if (newStrength == UNSET)
272+ return null;
273+ if (newChars.length() == 0) {
274+ throw new ParseException
275+ ("missing chars (=,;<&): " +
276+ pattern.substring(i,
277+ (i+10 < pattern.length()) ?
278+ i+10 : pattern.length()),
279+ i);
280+ }
281+
282+ return new PatternEntry(newStrength, newChars, newExtension);
283+ }
284+
285+ // We re-use these objects in order to improve performance
286+ private StringBuffer newChars = new StringBuffer();
287+ private StringBuffer newExtension = new StringBuffer();
288+
289+ }
290+
291+ static boolean isSpecialChar(char ch) {
292+ return ((ch == '\u0020') ||
293+ ((ch <= '\u002F') && (ch >= '\u0022')) ||
294+ ((ch <= '\u003F') && (ch >= '\u003A')) ||
295+ ((ch <= '\u0060') && (ch >= '\u005B')) ||
296+ ((ch <= '\u007E') && (ch >= '\u007B')));
297+ }
298+
299+
300+ static final int RESET = -2;
301+ static final int UNSET = -1;
302+
303+ int strength = UNSET;
304+ String chars = "";
305+ String extension = "";
306+}
java/pkg/java/text/RBCollationTables$1.class+0−0

Binary file not shown.

java/pkg/java/text/RBCollationTables$BuildAPI.class+0−0

Binary file not shown.

java/pkg/java/text/RBCollationTables.class+0−0

Binary file not shown.

java/pkg/java/text/RBCollationTables.java+303−0
@@ -0,0 +1,303 @@
1+/*
2+ * Copyright (c) 1999, 2003, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.util.Vector;
42+import sun.text.UCompactIntArray;
43+import sun.text.IntHashtable;
44+
45+/**
46+ * This class contains the static state of a RuleBasedCollator: The various
47+ * tables that are used by the collation routines. Several RuleBasedCollators
48+ * can share a single RBCollationTables object, easing memory requirements and
49+ * improving performance.
50+ */
51+final class RBCollationTables {
52+ //===========================================================================================
53+ // The following diagram shows the data structure of the RBCollationTables object.
54+ // Suppose we have the rule, where 'o-umlaut' is the unicode char 0x00F6.
55+ // "a, A < b, B < c, C, ch, cH, Ch, CH < d, D ... < o, O; 'o-umlaut'/E, 'O-umlaut'/E ...".
56+ // What the rule says is, sorts 'ch'ligatures and 'c' only with tertiary difference and
57+ // sorts 'o-umlaut' as if it's always expanded with 'e'.
58+ //
59+ // mapping table contracting list expanding list
60+ // (contains all unicode char
61+ // entries) ___ ____________ _________________________
62+ // ________ +>|_*_|->|'c' |v('c') | +>|v('o')|v('umlaut')|v('e')|
63+ // |_\u0001_|-> v('\u0001') | |_:_| |------------| | |-------------------------|
64+ // |_\u0002_|-> v('\u0002') | |_:_| |'ch'|v('ch')| | | : |
65+ // |____:___| | |_:_| |------------| | |-------------------------|
66+ // |____:___| | |'cH'|v('cH')| | | : |
67+ // |__'a'___|-> v('a') | |------------| | |-------------------------|
68+ // |__'b'___|-> v('b') | |'Ch'|v('Ch')| | | : |
69+ // |____:___| | |------------| | |-------------------------|
70+ // |____:___| | |'CH'|v('CH')| | | : |
71+ // |___'c'__|---------------- ------------ | |-------------------------|
72+ // |____:___| | | : |
73+ // |o-umlaut|---------------------------------------- |_________________________|
74+ // |____:___|
75+ //
76+ // Noted by Helena Shih on 6/23/97
77+ //============================================================================================
78+
79+ public RBCollationTables(String rules, int decmp) throws ParseException {
80+ this.rules = rules;
81+
82+ RBTableBuilder builder = new RBTableBuilder(new BuildAPI());
83+ builder.build(rules, decmp); // this object is filled in through
84+ // the BuildAPI object
85+ }
86+
87+ final class BuildAPI {
88+ /**
89+ * Private constructor. Prevents anyone else besides RBTableBuilder
90+ * from gaining direct access to the internals of this class.
91+ */
92+ private BuildAPI() {
93+ }
94+
95+ /**
96+ * This function is used by RBTableBuilder to fill in all the members of this
97+ * object. (Effectively, the builder class functions as a "friend" of this
98+ * class, but to avoid changing too much of the logic, it carries around "shadow"
99+ * copies of all these variables until the end of the build process and then
100+ * copies them en masse into the actual tables object once all the construction
101+ * logic is complete. This function does that "copying en masse".
102+ * @param f2ary The value for frenchSec (the French-secondary flag)
103+ * @param swap The value for SE Asian swapping rule
104+ * @param map The collator's character-mapping table (the value for mapping)
105+ * @param cTbl The collator's contracting-character table (the value for contractTable)
106+ * @param eTbl The collator's expanding-character table (the value for expandTable)
107+ * @param cFlgs The hash table of characters that participate in contracting-
108+ * character sequences (the value for contractFlags)
109+ * @param mso The value for maxSecOrder
110+ * @param mto The value for maxTerOrder
111+ */
112+ void fillInTables(boolean f2ary,
113+ boolean swap,
114+ UCompactIntArray map,
115+ Vector cTbl,
116+ Vector eTbl,
117+ IntHashtable cFlgs,
118+ short mso,
119+ short mto) {
120+ frenchSec = f2ary;
121+ seAsianSwapping = swap;
122+ mapping = map;
123+ contractTable = cTbl;
124+ expandTable = eTbl;
125+ contractFlags = cFlgs;
126+ maxSecOrder = mso;
127+ maxTerOrder = mto;
128+ }
129+ }
130+
131+ /**
132+ * Gets the table-based rules for the collation object.
133+ * @return returns the collation rules that the table collation object
134+ * was created from.
135+ */
136+ public String getRules()
137+ {
138+ return rules;
139+ }
140+
141+ public boolean isFrenchSec() {
142+ return frenchSec;
143+ }
144+
145+ public boolean isSEAsianSwapping() {
146+ return seAsianSwapping;
147+ }
148+
149+ // ==============================================================
150+ // internal (for use by CollationElementIterator)
151+ // ==============================================================
152+
153+ /**
154+ * Get the entry of hash table of the contracting string in the collation
155+ * table.
156+ * @param ch the starting character of the contracting string
157+ */
158+ Vector getContractValues(int ch)
159+ {
160+ int index = mapping.elementAt(ch);
161+ return getContractValuesImpl(index - CONTRACTCHARINDEX);
162+ }
163+
164+ //get contract values from contractTable by index
165+ private Vector getContractValuesImpl(int index)
166+ {
167+ if (index >= 0)
168+ {
169+ return (Vector)contractTable.elementAt(index);
170+ }
171+ else // not found
172+ {
173+ return null;
174+ }
175+ }
176+
177+ /**
178+ * Returns true if this character appears anywhere in a contracting
179+ * character sequence. (Used by CollationElementIterator.setOffset().)
180+ */
181+ boolean usedInContractSeq(int c) {
182+ return contractFlags.get(c) == 1;
183+ }
184+
185+ /**
186+ * Return the maximum length of any expansion sequences that end
187+ * with the specified comparison order.
188+ *
189+ * @param order a collation order returned by previous or next.
190+ * @return the maximum length of any expansion seuences ending
191+ * with the specified order.
192+ *
193+ * @see CollationElementIterator#getMaxExpansion
194+ */
195+ int getMaxExpansion(int order)
196+ {
197+ int result = 1;
198+
199+ if (expandTable != null) {
200+ // Right now this does a linear search through the entire
201+ // expandsion table. If a collator had a large number of expansions,
202+ // this could cause a performance problem, but in practise that
203+ // rarely happens
204+ for (int i = 0; i < expandTable.size(); i++) {
205+ int[] valueList = (int [])expandTable.elementAt(i);
206+ int length = valueList.length;
207+
208+ if (length > result && valueList[length-1] == order) {
209+ result = length;
210+ }
211+ }
212+ }
213+
214+ return result;
215+ }
216+
217+ /**
218+ * Get the entry of hash table of the expanding string in the collation
219+ * table.
220+ * @param idx the index of the expanding string value list
221+ */
222+ final int[] getExpandValueList(int order) {
223+ return (int[])expandTable.elementAt(order - EXPANDCHARINDEX);
224+ }
225+
226+ /**
227+ * Get the comarison order of a character from the collation table.
228+ * @return the comparison order of a character.
229+ */
230+ int getUnicodeOrder(int ch)
231+ {
232+ return mapping.elementAt(ch);
233+ }
234+
235+ short getMaxSecOrder() {
236+ return maxSecOrder;
237+ }
238+
239+ short getMaxTerOrder() {
240+ return maxTerOrder;
241+ }
242+
243+ /**
244+ * Reverse a string.
245+ */
246+ //shemran/Note: this is used for secondary order value reverse, no
247+ // need to consider supplementary pair.
248+ static void reverse (StringBuffer result, int from, int to)
249+ {
250+ int i = from;
251+ char swap;
252+
253+ int j = to - 1;
254+ while (i < j) {
255+ swap = result.charAt(i);
256+ result.setCharAt(i, result.charAt(j));
257+ result.setCharAt(j, swap);
258+ i++;
259+ j--;
260+ }
261+ }
262+
263+ final static int getEntry(Vector list, String name, boolean fwd) {
264+ for (int i = 0; i < list.size(); i++) {
265+ EntryPair pair = (EntryPair)list.elementAt(i);
266+ if (pair.fwd == fwd && pair.entryName.equals(name)) {
267+ return i;
268+ }
269+ }
270+ return UNMAPPED;
271+ }
272+
273+ // ==============================================================
274+ // constants
275+ // ==============================================================
276+ //sherman/Todo: is the value big enough?????
277+ final static int EXPANDCHARINDEX = 0x7E000000; // Expand index follows
278+ final static int CONTRACTCHARINDEX = 0x7F000000; // contract indexes follow
279+ final static int UNMAPPED = 0xFFFFFFFF;
280+
281+ final static int PRIMARYORDERMASK = 0xffff0000;
282+ final static int SECONDARYORDERMASK = 0x0000ff00;
283+ final static int TERTIARYORDERMASK = 0x000000ff;
284+ final static int PRIMARYDIFFERENCEONLY = 0xffff0000;
285+ final static int SECONDARYDIFFERENCEONLY = 0xffffff00;
286+ final static int PRIMARYORDERSHIFT = 16;
287+ final static int SECONDARYORDERSHIFT = 8;
288+
289+ // ==============================================================
290+ // instance variables
291+ // ==============================================================
292+ private String rules = null;
293+ private boolean frenchSec = false;
294+ private boolean seAsianSwapping = false;
295+
296+ private UCompactIntArray mapping = null;
297+ private Vector contractTable = null;
298+ private Vector expandTable = null;
299+ private IntHashtable contractFlags = null;
300+
301+ private short maxSecOrder = 0;
302+ private short maxTerOrder = 0;
303+}
java/pkg/java/text/RBTableBuilder.class+0−0

Binary file not shown.

java/pkg/java/text/RBTableBuilder.java+618−0
@@ -0,0 +1,618 @@
1+/*
2+ * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.util.Vector;
42+import sun.text.UCompactIntArray;
43+import sun.text.IntHashtable;
44+import sun.text.ComposedCharIter;
45+import sun.text.CollatorUtilities;
46+import sun.text.normalizer.NormalizerImpl;
47+
48+/**
49+ * This class contains all the code to parse a RuleBasedCollator pattern
50+ * and build a RBCollationTables object from it. A particular instance
51+ * of tis class exists only during the actual build process-- once an
52+ * RBCollationTables object has been built, the RBTableBuilder object
53+ * goes away. This object carries all of the state which is only needed
54+ * during the build process, plus a "shadow" copy of all of the state
55+ * that will go into the tables object itself. This object communicates
56+ * with RBCollationTables through a separate class, RBCollationTables.BuildAPI,
57+ * this is an inner class of RBCollationTables and provides a separate
58+ * private API for communication with RBTableBuilder.
59+ * This class isn't just an inner class of RBCollationTables itself because
60+ * of its large size. For source-code readability, it seemed better for the
61+ * builder to have its own source file.
62+ */
63+final class RBTableBuilder {
64+
65+ public RBTableBuilder(RBCollationTables.BuildAPI tables) {
66+ this.tables = tables;
67+ }
68+
69+ /**
70+ * Create a table-based collation object with the given rules.
71+ * This is the main function that actually builds the tables and
72+ * stores them back in the RBCollationTables object. It is called
73+ * ONLY by the RBCollationTables constructor.
74+ * @see java.util.RuleBasedCollator#RuleBasedCollator
75+ * @exception ParseException If the rules format is incorrect.
76+ */
77+
78+ public void build(String pattern, int decmp) throws ParseException
79+ {
80+ boolean isSource = true;
81+ int i = 0;
82+ String expChars;
83+ String groupChars;
84+ if (pattern.length() == 0)
85+ throw new ParseException("Build rules empty.", 0);
86+
87+ // This array maps Unicode characters to their collation ordering
88+ mapping = new UCompactIntArray((int)RBCollationTables.UNMAPPED);
89+ // Normalize the build rules. Find occurances of all decomposed characters
90+ // and normalize the rules before feeding into the builder. By "normalize",
91+ // we mean that all precomposed Unicode characters must be converted into
92+ // a base character and one or more combining characters (such as accents).
93+ // When there are multiple combining characters attached to a base character,
94+ // the combining characters must be in their canonical order
95+ //
96+ // sherman/Note:
97+ //(1)decmp will be NO_DECOMPOSITION only in ko locale to prevent decompose
98+ //hangual syllables to jamos, so we can actually just call decompose with
99+ //normalizer's IGNORE_HANGUL option turned on
100+ //
101+ //(2)just call the "special version" in NormalizerImpl directly
102+ //pattern = Normalizer.decompose(pattern, false, Normalizer.IGNORE_HANGUL, true);
103+ //
104+ //Normalizer.Mode mode = CollatorUtilities.toNormalizerMode(decmp);
105+ //pattern = Normalizer.normalize(pattern, mode, 0, true);
106+
107+ pattern = NormalizerImpl.canonicalDecomposeWithSingleQuotation(pattern);
108+
109+ // Build the merged collation entries
110+ // Since rules can be specified in any order in the string
111+ // (e.g. "c , C < d , D < e , E .... C < CH")
112+ // this splits all of the rules in the string out into separate
113+ // objects and then sorts them. In the above example, it merges the
114+ // "C < CH" rule in just before the "C < D" rule.
115+ //
116+
117+ mPattern = new MergeCollation(pattern);
118+
119+ int order = 0;
120+
121+ // Now walk though each entry and add it to my own tables
122+ for (i = 0; i < mPattern.getCount(); ++i)
123+ {
124+ PatternEntry entry = mPattern.getItemAt(i);
125+ if (entry != null) {
126+ groupChars = entry.getChars();
127+ if (groupChars.length() > 1) {
128+ switch(groupChars.charAt(groupChars.length()-1)) {
129+ case '@':
130+ frenchSec = true;
131+ groupChars = groupChars.substring(0, groupChars.length()-1);
132+ break;
133+ case '!':
134+ seAsianSwapping = true;
135+ groupChars = groupChars.substring(0, groupChars.length()-1);
136+ break;
137+ }
138+ }
139+
140+ order = increment(entry.getStrength(), order);
141+ expChars = entry.getExtension();
142+
143+ if (expChars.length() != 0) {
144+ addExpandOrder(groupChars, expChars, order);
145+ } else if (groupChars.length() > 1) {
146+ char ch = groupChars.charAt(0);
147+ if (Character.isHighSurrogate(ch) && groupChars.length() == 2) {
148+ addOrder(Character.toCodePoint(ch, groupChars.charAt(1)), order);
149+ } else {
150+ addContractOrder(groupChars, order);
151+ }
152+ } else {
153+ char ch = groupChars.charAt(0);
154+ addOrder(ch, order);
155+ }
156+ }
157+ }
158+ addComposedChars();
159+
160+ commit();
161+ mapping.compact();
162+ /*
163+ System.out.println("mappingSize=" + mapping.getKSize());
164+ for (int j = 0; j < 0xffff; j++) {
165+ int value = mapping.elementAt(j);
166+ if (value != RBCollationTables.UNMAPPED)
167+ System.out.println("index=" + Integer.toString(j, 16)
168+ + ", value=" + Integer.toString(value, 16));
169+ }
170+ */
171+ tables.fillInTables(frenchSec, seAsianSwapping, mapping, contractTable, expandTable,
172+ contractFlags, maxSecOrder, maxTerOrder);
173+ }
174+
175+ /** Add expanding entries for pre-composed unicode characters so that this
176+ * collator can be used reasonably well with decomposition turned off.
177+ */
178+ private void addComposedChars() throws ParseException {
179+ // Iterate through all of the pre-composed characters in Unicode
180+ ComposedCharIter iter = new ComposedCharIter();
181+ int c;
182+ while ((c = iter.next()) != ComposedCharIter.DONE) {
183+ if (getCharOrder(c) == RBCollationTables.UNMAPPED) {
184+ //
185+ // We don't already have an ordering for this pre-composed character.
186+ //
187+ // First, see if the decomposed string is already in our
188+ // tables as a single contracting-string ordering.
189+ // If so, just map the precomposed character to that order.
190+ //
191+ // TODO: What we should really be doing here is trying to find the
192+ // longest initial substring of the decomposition that is present
193+ // in the tables as a contracting character sequence, and find its
194+ // ordering. Then do this recursively with the remaining chars
195+ // so that we build a list of orderings, and add that list to
196+ // the expansion table.
197+ // That would be more correct but also significantly slower, so
198+ // I'm not totally sure it's worth doing.
199+ //
200+ String s = iter.decomposition();
201+
202+ //sherman/Note: if this is 1 character decomposed string, the
203+ //only thing need to do is to check if this decomposed character
204+ //has an entry in our order table, this order is not necessary
205+ //to be a contraction order, if it does have one, add an entry
206+ //for the precomposed character by using the same order, the
207+ //previous impl unnecessarily adds a single character expansion
208+ //entry.
209+ if (s.length() == 1) {
210+ int order = getCharOrder(s.charAt(0));
211+ if (order != RBCollationTables.UNMAPPED) {
212+ addOrder(c, order);
213+ }
214+ continue;
215+ } else if (s.length() == 2) {
216+ char ch0 = s.charAt(0);
217+ if (Character.isHighSurrogate(ch0)) {
218+ int order = getCharOrder(s.codePointAt(0));
219+ if (order != RBCollationTables.UNMAPPED) {
220+ addOrder(c, order);
221+ }
222+ continue;
223+ }
224+ }
225+ int contractOrder = getContractOrder(s);
226+ if (contractOrder != RBCollationTables.UNMAPPED) {
227+ addOrder(c, contractOrder);
228+ } else {
229+ //
230+ // We don't have a contracting ordering for the entire string
231+ // that results from the decomposition, but if we have orders
232+ // for each individual character, we can add an expanding
233+ // table entry for the pre-composed character
234+ //
235+ boolean allThere = true;
236+ for (int i = 0; i < s.length(); i++) {
237+ if (getCharOrder(s.charAt(i)) == RBCollationTables.UNMAPPED) {
238+ allThere = false;
239+ break;
240+ }
241+ }
242+ if (allThere) {
243+ addExpandOrder(c, s, RBCollationTables.UNMAPPED);
244+ }
245+ }
246+ }
247+ }
248+ }
249+
250+ /**
251+ * Look up for unmapped values in the expanded character table.
252+ *
253+ * When the expanding character tables are built by addExpandOrder,
254+ * it doesn't know what the final ordering of each character
255+ * in the expansion will be. Instead, it just puts the raw character
256+ * code into the table, adding CHARINDEX as a flag. Now that we've
257+ * finished building the mapping table, we can go back and look up
258+ * that character to see what its real collation order is and
259+ * stick that into the expansion table. That lets us avoid doing
260+ * a two-stage lookup later.
261+ */
262+ private final void commit()
263+ {
264+ if (expandTable != null) {
265+ for (int i = 0; i < expandTable.size(); i++) {
266+ int[] valueList = (int [])expandTable.elementAt(i);
267+ for (int j = 0; j < valueList.length; j++) {
268+ int order = valueList[j];
269+ if (order < RBCollationTables.EXPANDCHARINDEX && order > CHARINDEX) {
270+ // found a expanding character that isn't filled in yet
271+ int ch = order - CHARINDEX;
272+
273+ // Get the real values for the non-filled entry
274+ int realValue = getCharOrder(ch);
275+
276+ if (realValue == RBCollationTables.UNMAPPED) {
277+ // The real value is still unmapped, maybe it's ignorable
278+ valueList[j] = IGNORABLEMASK & ch;
279+ } else {
280+ // just fill in the value
281+ valueList[j] = realValue;
282+ }
283+ }
284+ }
285+ }
286+ }
287+ }
288+ /**
289+ * Increment of the last order based on the comparison level.
290+ */
291+ private final int increment(int aStrength, int lastValue)
292+ {
293+ switch(aStrength)
294+ {
295+ case Collator.PRIMARY:
296+ // increment priamry order and mask off secondary and tertiary difference
297+ lastValue += PRIMARYORDERINCREMENT;
298+ lastValue &= RBCollationTables.PRIMARYORDERMASK;
299+ isOverIgnore = true;
300+ break;
301+ case Collator.SECONDARY:
302+ // increment secondary order and mask off tertiary difference
303+ lastValue += SECONDARYORDERINCREMENT;
304+ lastValue &= RBCollationTables.SECONDARYDIFFERENCEONLY;
305+ // record max # of ignorable chars with secondary difference
306+ if (!isOverIgnore)
307+ maxSecOrder++;
308+ break;
309+ case Collator.TERTIARY:
310+ // increment tertiary order
311+ lastValue += TERTIARYORDERINCREMENT;
312+ // record max # of ignorable chars with tertiary difference
313+ if (!isOverIgnore)
314+ maxTerOrder++;
315+ break;
316+ }
317+ return lastValue;
318+ }
319+
320+ /**
321+ * Adds a character and its designated order into the collation table.
322+ */
323+ private final void addOrder(int ch, int anOrder)
324+ {
325+ // See if the char already has an order in the mapping table
326+ int order = mapping.elementAt(ch);
327+
328+ if (order >= RBCollationTables.CONTRACTCHARINDEX) {
329+ // There's already an entry for this character that points to a contracting
330+ // character table. Instead of adding the character directly to the mapping
331+ // table, we must add it to the contract table instead.
332+ int length = 1;
333+ if (Character.isSupplementaryCodePoint(ch)) {
334+ length = Character.toChars(ch, keyBuf, 0);
335+ } else {
336+ keyBuf[0] = (char)ch;
337+ }
338+ addContractOrder(new String(keyBuf, 0, length), anOrder);
339+ } else {
340+ // add the entry to the mapping table,
341+ // the same later entry replaces the previous one
342+ mapping.setElementAt(ch, anOrder);
343+ }
344+ }
345+
346+ private final void addContractOrder(String groupChars, int anOrder) {
347+ addContractOrder(groupChars, anOrder, true);
348+ }
349+
350+ /**
351+ * Adds the contracting string into the collation table.
352+ */
353+ private final void addContractOrder(String groupChars, int anOrder,
354+ boolean fwd)
355+ {
356+ if (contractTable == null) {
357+ contractTable = new Vector(INITIALTABLESIZE);
358+ }
359+
360+ //initial character
361+ int ch = groupChars.codePointAt(0);
362+ /*
363+ char ch0 = groupChars.charAt(0);
364+ int ch = Character.isHighSurrogate(ch0)?
365+ Character.toCodePoint(ch0, groupChars.charAt(1)):ch0;
366+ */
367+ // See if the initial character of the string already has a contract table.
368+ int entry = mapping.elementAt(ch);
369+ Vector entryTable = getContractValuesImpl(entry - RBCollationTables.CONTRACTCHARINDEX);
370+
371+ if (entryTable == null) {
372+ // We need to create a new table of contract entries for this base char
373+ int tableIndex = RBCollationTables.CONTRACTCHARINDEX + contractTable.size();
374+ entryTable = new Vector(INITIALTABLESIZE);
375+ contractTable.addElement(entryTable);
376+
377+ // Add the initial character's current ordering first. then
378+ // update its mapping to point to this contract table
379+ entryTable.addElement(new EntryPair(groupChars.substring(0,Character.charCount(ch)), entry));
380+ mapping.setElementAt(ch, tableIndex);
381+ }
382+
383+ // Now add (or replace) this string in the table
384+ int index = RBCollationTables.getEntry(entryTable, groupChars, fwd);
385+ if (index != RBCollationTables.UNMAPPED) {
386+ EntryPair pair = (EntryPair) entryTable.elementAt(index);
387+ pair.value = anOrder;
388+ } else {
389+ EntryPair pair = (EntryPair)entryTable.lastElement();
390+
391+ // NOTE: This little bit of logic is here to speed CollationElementIterator
392+ // .nextContractChar(). This code ensures that the longest sequence in
393+ // this list is always the _last_ one in the list. This keeps
394+ // nextContractChar() from having to search the entire list for the longest
395+ // sequence.
396+ if (groupChars.length() > pair.entryName.length()) {
397+ entryTable.addElement(new EntryPair(groupChars, anOrder, fwd));
398+ } else {
399+ entryTable.insertElementAt(new EntryPair(groupChars, anOrder,
400+ fwd), entryTable.size() - 1);
401+ }
402+ }
403+
404+ // If this was a forward mapping for a contracting string, also add a
405+ // reverse mapping for it, so that CollationElementIterator.previous
406+ // can work right
407+ if (fwd && groupChars.length() > 1) {
408+ addContractFlags(groupChars);
409+ addContractOrder(new StringBuffer(groupChars).reverse().toString(),
410+ anOrder, false);
411+ }
412+ }
413+
414+ /**
415+ * If the given string has been specified as a contracting string
416+ * in this collation table, return its ordering.
417+ * Otherwise return UNMAPPED.
418+ */
419+ private int getContractOrder(String groupChars)
420+ {
421+ int result = RBCollationTables.UNMAPPED;
422+ if (contractTable != null) {
423+ int ch = groupChars.codePointAt(0);
424+ /*
425+ char ch0 = groupChars.charAt(0);
426+ int ch = Character.isHighSurrogate(ch0)?
427+ Character.toCodePoint(ch0, groupChars.charAt(1)):ch0;
428+ */
429+ Vector entryTable = getContractValues(ch);
430+ if (entryTable != null) {
431+ int index = RBCollationTables.getEntry(entryTable, groupChars, true);
432+ if (index != RBCollationTables.UNMAPPED) {
433+ EntryPair pair = (EntryPair) entryTable.elementAt(index);
434+ result = pair.value;
435+ }
436+ }
437+ }
438+ return result;
439+ }
440+
441+ private final int getCharOrder(int ch) {
442+ int order = mapping.elementAt(ch);
443+
444+ if (order >= RBCollationTables.CONTRACTCHARINDEX) {
445+ Vector groupList = getContractValuesImpl(order - RBCollationTables.CONTRACTCHARINDEX);
446+ EntryPair pair = (EntryPair)groupList.firstElement();
447+ order = pair.value;
448+ }
449+ return order;
450+ }
451+
452+ /**
453+ * Get the entry of hash table of the contracting string in the collation
454+ * table.
455+ * @param ch the starting character of the contracting string
456+ */
457+ private Vector getContractValues(int ch)
458+ {
459+ int index = mapping.elementAt(ch);
460+ return getContractValuesImpl(index - RBCollationTables.CONTRACTCHARINDEX);
461+ }
462+
463+ private Vector getContractValuesImpl(int index)
464+ {
465+ if (index >= 0)
466+ {
467+ return (Vector)contractTable.elementAt(index);
468+ }
469+ else // not found
470+ {
471+ return null;
472+ }
473+ }
474+
475+ /**
476+ * Adds the expanding string into the collation table.
477+ */
478+ private final void addExpandOrder(String contractChars,
479+ String expandChars,
480+ int anOrder) throws ParseException
481+ {
482+ // Create an expansion table entry
483+ int tableIndex = addExpansion(anOrder, expandChars);
484+
485+ // And add its index into the main mapping table
486+ if (contractChars.length() > 1) {
487+ char ch = contractChars.charAt(0);
488+ if (Character.isHighSurrogate(ch) && contractChars.length() == 2) {
489+ char ch2 = contractChars.charAt(1);
490+ if (Character.isLowSurrogate(ch2)) {
491+ //only add into table when it is a legal surrogate
492+ addOrder(Character.toCodePoint(ch, ch2), tableIndex);
493+ }
494+ } else {
495+ addContractOrder(contractChars, tableIndex);
496+ }
497+ } else {
498+ addOrder(contractChars.charAt(0), tableIndex);
499+ }
500+ }
501+
502+ private final void addExpandOrder(int ch, String expandChars, int anOrder)
503+ throws ParseException
504+ {
505+ int tableIndex = addExpansion(anOrder, expandChars);
506+ addOrder(ch, tableIndex);
507+ }
508+
509+ /**
510+ * Create a new entry in the expansion table that contains the orderings
511+ * for the given characers. If anOrder is valid, it is added to the
512+ * beginning of the expanded list of orders.
513+ */
514+ private int addExpansion(int anOrder, String expandChars) {
515+ if (expandTable == null) {
516+ expandTable = new Vector(INITIALTABLESIZE);
517+ }
518+
519+ // If anOrder is valid, we want to add it at the beginning of the list
520+ int offset = (anOrder == RBCollationTables.UNMAPPED) ? 0 : 1;
521+
522+ int[] valueList = new int[expandChars.length() + offset];
523+ if (offset == 1) {
524+ valueList[0] = anOrder;
525+ }
526+
527+ int j = offset;
528+ for (int i = 0; i < expandChars.length(); i++) {
529+ char ch0 = expandChars.charAt(i);
530+ char ch1;
531+ int ch;
532+ if (Character.isHighSurrogate(ch0)) {
533+ if (++i == expandChars.length() ||
534+ !Character.isLowSurrogate(ch1=expandChars.charAt(i))) {
535+ //ether we are missing the low surrogate or the next char
536+ //is not a legal low surrogate, so stop loop
537+ break;
538+ }
539+ ch = Character.toCodePoint(ch0, ch1);
540+
541+ } else {
542+ ch = ch0;
543+ }
544+
545+ int mapValue = getCharOrder(ch);
546+
547+ if (mapValue != RBCollationTables.UNMAPPED) {
548+ valueList[j++] = mapValue;
549+ } else {
550+ // can't find it in the table, will be filled in by commit().
551+ valueList[j++] = CHARINDEX + ch;
552+ }
553+ }
554+ if (j < valueList.length) {
555+ //we had at least one supplementary character, the size of valueList
556+ //is bigger than it really needs...
557+ int[] tmpBuf = new int[j];
558+ while (--j >= 0) {
559+ tmpBuf[j] = valueList[j];
560+ }
561+ valueList = tmpBuf;
562+ }
563+ // Add the expanding char list into the expansion table.
564+ int tableIndex = RBCollationTables.EXPANDCHARINDEX + expandTable.size();
565+ expandTable.addElement(valueList);
566+
567+ return tableIndex;
568+ }
569+
570+ private void addContractFlags(String chars) {
571+ char c0;
572+ int c;
573+ int len = chars.length();
574+ for (int i = 0; i < len; i++) {
575+ c0 = chars.charAt(i);
576+ c = Character.isHighSurrogate(c0)
577+ ?Character.toCodePoint(c0, chars.charAt(++i))
578+ :c0;
579+ contractFlags.put(c, 1);
580+ }
581+ }
582+
583+ // ==============================================================
584+ // constants
585+ // ==============================================================
586+ final static int CHARINDEX = 0x70000000; // need look up in .commit()
587+
588+ private final static int IGNORABLEMASK = 0x0000ffff;
589+ private final static int PRIMARYORDERINCREMENT = 0x00010000;
590+ private final static int SECONDARYORDERINCREMENT = 0x00000100;
591+ private final static int TERTIARYORDERINCREMENT = 0x00000001;
592+ private final static int INITIALTABLESIZE = 20;
593+ private final static int MAXKEYSIZE = 5;
594+
595+ // ==============================================================
596+ // instance variables
597+ // ==============================================================
598+
599+ // variables used by the build process
600+ private RBCollationTables.BuildAPI tables = null;
601+ private MergeCollation mPattern = null;
602+ private boolean isOverIgnore = false;
603+ private char[] keyBuf = new char[MAXKEYSIZE];
604+ private IntHashtable contractFlags = new IntHashtable(100);
605+
606+ // "shadow" copies of the instance variables in RBCollationTables
607+ // (the values in these variables are copied back into RBCollationTables
608+ // at the end of the build process)
609+ private boolean frenchSec = false;
610+ private boolean seAsianSwapping = false;
611+
612+ private UCompactIntArray mapping = null;
613+ private Vector contractTable = null;
614+ private Vector expandTable = null;
615+
616+ private short maxSecOrder = 0;
617+ private short maxTerOrder = 0;
618+}
java/pkg/java/text/RuleBasedBreakIterator$1.class+0−0

Binary file not shown.

java/pkg/java/text/RuleBasedBreakIterator$SafeCharIterator.class+0−0

Binary file not shown.

java/pkg/java/text/RuleBasedBreakIterator.class+0−0

Binary file not shown.

java/pkg/java/text/RuleBasedBreakIterator.java+1148−0
@@ -0,0 +1,1148 @@
1+/*
2+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ *
28+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
29+ * (C) Copyright IBM Corp. 1996 - 2002 - All Rights Reserved
30+ *
31+ * The original version of this source code and documentation
32+ * is copyrighted and owned by Taligent, Inc., a wholly-owned
33+ * subsidiary of IBM. These materials are provided under terms
34+ * of a License Agreement between Taligent and Sun. This technology
35+ * is protected by multiple US and International patents.
36+ *
37+ * This notice and attribution to Taligent may not be removed.
38+ * Taligent is a registered trademark of Taligent, Inc.
39+ */
40+
41+package java.text;
42+
43+import java.io.BufferedInputStream;
44+import java.io.IOException;
45+import java.security.AccessController;
46+import java.security.PrivilegedActionException;
47+import java.security.PrivilegedExceptionAction;
48+import java.util.Vector;
49+import java.util.Stack;
50+import java.util.Hashtable;
51+import java.util.Enumeration;
52+import java.util.MissingResourceException;
53+import java.text.CharacterIterator;
54+import java.text.StringCharacterIterator;
55+import sun.text.CompactByteArray;
56+import sun.text.SupplementaryCharacterData;
57+
58+/**
59+ * <p>A subclass of BreakIterator whose behavior is specified using a list of rules.</p>
60+ *
61+ * <p>There are two kinds of rules, which are separated by semicolons: <i>substitutions</i>
62+ * and <i>regular expressions.</i></p>
63+ *
64+ * <p>A substitution rule defines a name that can be used in place of an expression. It
65+ * consists of a name, which is a string of characters contained in angle brackets, an equals
66+ * sign, and an expression. (There can be no whitespace on either side of the equals sign.)
67+ * To keep its syntactic meaning intact, the expression must be enclosed in parentheses or
68+ * square brackets. A substitution is visible after its definition, and is filled in using
69+ * simple textual substitution. Substitution definitions can contain other substitutions, as
70+ * long as those substitutions have been defined first. Substitutions are generally used to
71+ * make the regular expressions (which can get quite complex) shorted and easier to read.
72+ * They typically define either character categories or commonly-used subexpressions.</p>
73+ *
74+ * <p>There is one special substitution.&nbsp; If the description defines a substitution
75+ * called &quot;&lt;ignore&gt;&quot;, the expression must be a [] expression, and the
76+ * expression defines a set of characters (the &quot;<em>ignore characters</em>&quot;) that
77+ * will be transparent to the BreakIterator.&nbsp; A sequence of characters will break the
78+ * same way it would if any ignore characters it contains are taken out.&nbsp; Break
79+ * positions never occur befoer ignore characters.</p>
80+ *
81+ * <p>A regular expression uses a subset of the normal Unix regular-expression syntax, and
82+ * defines a sequence of characters to be kept together. With one significant exception, the
83+ * iterator uses a longest-possible-match algorithm when matching text to regular
84+ * expressions. The iterator also treats descriptions containing multiple regular expressions
85+ * as if they were ORed together (i.e., as if they were separated by |).</p>
86+ *
87+ * <p>The special characters recognized by the regular-expression parser are as follows:</p>
88+ *
89+ * <blockquote>
90+ * <table border="1" width="100%">
91+ * <tr>
92+ * <td width="6%">*</td>
93+ * <td width="94%">Specifies that the expression preceding the asterisk may occur any number
94+ * of times (including not at all).</td>
95+ * </tr>
96+ * <tr>
97+ * <td width="6%">{}</td>
98+ * <td width="94%">Encloses a sequence of characters that is optional.</td>
99+ * </tr>
100+ * <tr>
101+ * <td width="6%">()</td>
102+ * <td width="94%">Encloses a sequence of characters.&nbsp; If followed by *, the sequence
103+ * repeats.&nbsp; Otherwise, the parentheses are just a grouping device and a way to delimit
104+ * the ends of expressions containing |.</td>
105+ * </tr>
106+ * <tr>
107+ * <td width="6%">|</td>
108+ * <td width="94%">Separates two alternative sequences of characters.&nbsp; Either one
109+ * sequence or the other, but not both, matches this expression.&nbsp; The | character can
110+ * only occur inside ().</td>
111+ * </tr>
112+ * <tr>
113+ * <td width="6%">.</td>
114+ * <td width="94%">Matches any character.</td>
115+ * </tr>
116+ * <tr>
117+ * <td width="6%">*?</td>
118+ * <td width="94%">Specifies a non-greedy asterisk.&nbsp; *? works the same way as *, except
119+ * when there is overlap between the last group of characters in the expression preceding the
120+ * * and the first group of characters following the *.&nbsp; When there is this kind of
121+ * overlap, * will match the longest sequence of characters that match the expression before
122+ * the *, and *? will match the shortest sequence of characters matching the expression
123+ * before the *?.&nbsp; For example, if you have &quot;xxyxyyyxyxyxxyxyxyy&quot; in the text,
124+ * &quot;x[xy]*x&quot; will match through to the last x (i.e., &quot;<strong>xxyxyyyxyxyxxyxyx</strong>yy&quot;,
125+ * but &quot;x[xy]*?x&quot; will only match the first two xes (&quot;<strong>xx</strong>yxyyyxyxyxxyxyxyy&quot;).</td>
126+ * </tr>
127+ * <tr>
128+ * <td width="6%">[]</td>
129+ * <td width="94%">Specifies a group of alternative characters.&nbsp; A [] expression will
130+ * match any single character that is specified in the [] expression.&nbsp; For more on the
131+ * syntax of [] expressions, see below.</td>
132+ * </tr>
133+ * <tr>
134+ * <td width="6%">/</td>
135+ * <td width="94%">Specifies where the break position should go if text matches this
136+ * expression.&nbsp; (e.g., &quot;[a-z]&#42;/[:Zs:]*[1-0]&quot; will match if the iterator sees a run
137+ * of letters, followed by a run of whitespace, followed by a digit, but the break position
138+ * will actually go before the whitespace).&nbsp; Expressions that don't contain / put the
139+ * break position at the end of the matching text.</td>
140+ * </tr>
141+ * <tr>
142+ * <td width="6%">\</td>
143+ * <td width="94%">Escape character.&nbsp; The \ itself is ignored, but causes the next
144+ * character to be treated as literal character.&nbsp; This has no effect for many
145+ * characters, but for the characters listed above, this deprives them of their special
146+ * meaning.&nbsp; (There are no special escape sequences for Unicode characters, or tabs and
147+ * newlines; these are all handled by a higher-level protocol.&nbsp; In a Java string,
148+ * &quot;\n&quot; will be converted to a literal newline character by the time the
149+ * regular-expression parser sees it.&nbsp; Of course, this means that \ sequences that are
150+ * visible to the regexp parser must be written as \\ when inside a Java string.)&nbsp; All
151+ * characters in the ASCII range except for letters, digits, and control characters are
152+ * reserved characters to the parser and must be preceded by \ even if they currently don't
153+ * mean anything.</td>
154+ * </tr>
155+ * <tr>
156+ * <td width="6%">!</td>
157+ * <td width="94%">If ! appears at the beginning of a regular expression, it tells the regexp
158+ * parser that this expression specifies the backwards-iteration behavior of the iterator,
159+ * and not its normal iteration behavior.&nbsp; This is generally only used in situations
160+ * where the automatically-generated backwards-iteration brhavior doesn't produce
161+ * satisfactory results and must be supplemented with extra client-specified rules.</td>
162+ * </tr>
163+ * <tr>
164+ * <td width="6%"><em>(all others)</em></td>
165+ * <td width="94%">All other characters are treated as literal characters, which must match
166+ * the corresponding character(s) in the text exactly.</td>
167+ * </tr>
168+ * </table>
169+ * </blockquote>
170+ *
171+ * <p>Within a [] expression, a number of other special characters can be used to specify
172+ * groups of characters:</p>
173+ *
174+ * <blockquote>
175+ * <table border="1" width="100%">
176+ * <tr>
177+ * <td width="6%">-</td>
178+ * <td width="94%">Specifies a range of matching characters.&nbsp; For example
179+ * &quot;[a-p]&quot; matches all lowercase Latin letters from a to p (inclusive).&nbsp; The -
180+ * sign specifies ranges of continuous Unicode numeric values, not ranges of characters in a
181+ * language's alphabetical order: &quot;[a-z]&quot; doesn't include capital letters, nor does
182+ * it include accented letters such as a-umlaut.</td>
183+ * </tr>
184+ * <tr>
185+ * <td width="6%">::</td>
186+ * <td width="94%">A pair of colons containing a one- or two-letter code matches all
187+ * characters in the corresponding Unicode category.&nbsp; The two-letter codes are the same
188+ * as the two-letter codes in the Unicode database (for example, &quot;[:Sc::Sm:]&quot;
189+ * matches all currency symbols and all math symbols).&nbsp; Specifying a one-letter code is
190+ * the same as specifying all two-letter codes that begin with that letter (for example,
191+ * &quot;[:L:]&quot; matches all letters, and is equivalent to
192+ * &quot;[:Lu::Ll::Lo::Lm::Lt:]&quot;).&nbsp; Anything other than a valid two-letter Unicode
193+ * category code or a single letter that begins a Unicode category code is illegal within
194+ * colons.</td>
195+ * </tr>
196+ * <tr>
197+ * <td width="6%">[]</td>
198+ * <td width="94%">[] expressions can nest.&nbsp; This has no effect, except when used in
199+ * conjunction with the ^ token.</td>
200+ * </tr>
201+ * <tr>
202+ * <td width="6%">^</td>
203+ * <td width="94%">Excludes the character (or the characters in the [] expression) following
204+ * it from the group of characters.&nbsp; For example, &quot;[a-z^p]&quot; matches all Latin
205+ * lowercase letters except p.&nbsp; &quot;[:L:^[&#92;u4e00-&#92;u9fff]]&quot; matches all letters
206+ * except the Han ideographs.</td>
207+ * </tr>
208+ * <tr>
209+ * <td width="6%"><em>(all others)</em></td>
210+ * <td width="94%">All other characters are treated as literal characters.&nbsp; (For
211+ * example, &quot;[aeiou]&quot; specifies just the letters a, e, i, o, and u.)</td>
212+ * </tr>
213+ * </table>
214+ * </blockquote>
215+ *
216+ * <p>For a more complete explanation, see <a
217+ * href="http://www.ibm.com/java/education/boundaries/boundaries.html">http://www.ibm.com/java/education/boundaries/boundaries.html</a>.
218+ * &nbsp; For examples, see the resource data (which is annotated).</p>
219+ *
220+ * @author Richard Gillam
221+ */
222+class RuleBasedBreakIterator extends BreakIterator {
223+
224+ /**
225+ * A token used as a character-category value to identify ignore characters
226+ */
227+ protected static final byte IGNORE = -1;
228+
229+ /**
230+ * The state number of the starting state
231+ */
232+ private static final short START_STATE = 1;
233+
234+ /**
235+ * The state-transition value indicating "stop"
236+ */
237+ private static final short STOP_STATE = 0;
238+
239+ /**
240+ * Magic number for the BreakIterator data file format.
241+ */
242+ static final byte[] LABEL = {
243+ (byte)'B', (byte)'I', (byte)'d', (byte)'a', (byte)'t', (byte)'a',
244+ (byte)'\0'
245+ };
246+ static final int LABEL_LENGTH = LABEL.length;
247+
248+ /**
249+ * Version number of the dictionary that was read in.
250+ */
251+ static final byte supportedVersion = 1;
252+
253+ /**
254+ * Header size in byte count
255+ */
256+ private static final int HEADER_LENGTH = 36;
257+
258+ /**
259+ * An array length of indices for BMP characters
260+ */
261+ private static final int BMP_INDICES_LENGTH = 512;
262+
263+ /**
264+ * Tables that indexes from character values to character category numbers
265+ */
266+ private CompactByteArray charCategoryTable = null;
267+ private SupplementaryCharacterData supplementaryCharCategoryTable = null;
268+
269+ /**
270+ * The table of state transitions used for forward iteration
271+ */
272+ private short[] stateTable = null;
273+
274+ /**
275+ * The table of state transitions used to sync up the iterator with the
276+ * text in backwards and random-access iteration
277+ */
278+ private short[] backwardsStateTable = null;
279+
280+ /**
281+ * A list of flags indicating which states in the state table are accepting
282+ * ("end") states
283+ */
284+ private boolean[] endStates = null;
285+
286+ /**
287+ * A list of flags indicating which states in the state table are
288+ * lookahead states (states which turn lookahead on and off)
289+ */
290+ private boolean[] lookaheadStates = null;
291+
292+ /**
293+ * A table for additional data. May be used by a subclass of
294+ * RuleBasedBreakIterator.
295+ */
296+ private byte[] additionalData = null;
297+
298+ /**
299+ * The number of character categories (and, thus, the number of columns in
300+ * the state tables)
301+ */
302+ private int numCategories;
303+
304+ /**
305+ * The character iterator through which this BreakIterator accesses the text
306+ */
307+ private CharacterIterator text = null;
308+
309+ /**
310+ * A CRC32 value of all data in datafile
311+ */
312+ private long checksum;
313+
314+ //=======================================================================
315+ // constructors
316+ //=======================================================================
317+
318+ /**
319+ * Constructs a RuleBasedBreakIterator according to the datafile
320+ * provided.
321+ */
322+ public RuleBasedBreakIterator(String datafile)
323+ throws IOException, MissingResourceException {
324+ readTables(datafile);
325+ }
326+
327+ /**
328+ * Read datafile. The datafile's format is as follows:
329+ * <pre>
330+ * BreakIteratorData {
331+ * u1 magic[7];
332+ * u1 version;
333+ * u4 totalDataSize;
334+ * header_info header;
335+ * body value;
336+ * }
337+ * </pre>
338+ * <code>totalDataSize</code> is the summation of the size of
339+ * <code>header_info</code> and <code>body</code> in byte count.
340+ * <p>
341+ * In <code>header</code>, each field except for checksum implies the
342+ * length of each field. Since <code>BMPdataLength</code> is a fixed-length
343+ * data(512 entries), its length isn't included in <code>header</code>.
344+ * <code>checksum</code> is a CRC32 value of all in <code>body</code>.
345+ * <pre>
346+ * header_info {
347+ * u4 stateTableLength;
348+ * u4 backwardsStateTableLength;
349+ * u4 endStatesLength;
350+ * u4 lookaheadStatesLength;
351+ * u4 BMPdataLength;
352+ * u4 nonBMPdataLength;
353+ * u4 additionalDataLength;
354+ * u8 checksum;
355+ * }
356+ * </pre>
357+ * <p>
358+ *
359+ * Finally, <code>BMPindices</code> and <code>BMPdata</code> are set to
360+ * <code>charCategoryTable</code>. <code>nonBMPdata</code> is set to
361+ * <code>supplementaryCharCategoryTable</code>.
362+ * <pre>
363+ * body {
364+ * u2 stateTable[stateTableLength];
365+ * u2 backwardsStateTable[backwardsStateTableLength];
366+ * u1 endStates[endStatesLength];
367+ * u1 lookaheadStates[lookaheadStatesLength];
368+ * u2 BMPindices[512];
369+ * u1 BMPdata[BMPdataLength];
370+ * u4 nonBMPdata[numNonBMPdataLength];
371+ * u1 additionalData[additionalDataLength];
372+ * }
373+ * </pre>
374+ */
375+ protected void readTables(String datafile)
376+ throws IOException, MissingResourceException {
377+
378+ byte[] buffer = readFile(datafile);
379+
380+ /* Read header_info. */
381+ int stateTableLength = BreakIterator.getInt(buffer, 0);
382+ int backwardsStateTableLength = BreakIterator.getInt(buffer, 4);
383+ int endStatesLength = BreakIterator.getInt(buffer, 8);
384+ int lookaheadStatesLength = BreakIterator.getInt(buffer, 12);
385+ int BMPdataLength = BreakIterator.getInt(buffer, 16);
386+ int nonBMPdataLength = BreakIterator.getInt(buffer, 20);
387+ int additionalDataLength = BreakIterator.getInt(buffer, 24);
388+ checksum = BreakIterator.getLong(buffer, 28);
389+
390+ /* Read stateTable[numCategories * numRows] */
391+ stateTable = new short[stateTableLength];
392+ int offset = HEADER_LENGTH;
393+ for (int i = 0; i < stateTableLength; i++, offset+=2) {
394+ stateTable[i] = BreakIterator.getShort(buffer, offset);
395+ }
396+
397+ /* Read backwardsStateTable[numCategories * numRows] */
398+ backwardsStateTable = new short[backwardsStateTableLength];
399+ for (int i = 0; i < backwardsStateTableLength; i++, offset+=2) {
400+ backwardsStateTable[i] = BreakIterator.getShort(buffer, offset);
401+ }
402+
403+ /* Read endStates[numRows] */
404+ endStates = new boolean[endStatesLength];
405+ for (int i = 0; i < endStatesLength; i++, offset++) {
406+ endStates[i] = buffer[offset] == 1;
407+ }
408+
409+ /* Read lookaheadStates[numRows] */
410+ lookaheadStates = new boolean[lookaheadStatesLength];
411+ for (int i = 0; i < lookaheadStatesLength; i++, offset++) {
412+ lookaheadStates[i] = buffer[offset] == 1;
413+ }
414+
415+ /* Read a category table and indices for BMP characters. */
416+ short[] temp1 = new short[BMP_INDICES_LENGTH]; // BMPindices
417+ for (int i = 0; i < BMP_INDICES_LENGTH; i++, offset+=2) {
418+ temp1[i] = BreakIterator.getShort(buffer, offset);
419+ }
420+ byte[] temp2 = new byte[BMPdataLength]; // BMPdata
421+ System.arraycopy(buffer, offset, temp2, 0, BMPdataLength);
422+ offset += BMPdataLength;
423+ charCategoryTable = new CompactByteArray(temp1, temp2);
424+
425+ /* Read a category table for non-BMP characters. */
426+ int[] temp3 = new int[nonBMPdataLength];
427+ for (int i = 0; i < nonBMPdataLength; i++, offset+=4) {
428+ temp3[i] = BreakIterator.getInt(buffer, offset);
429+ }
430+ supplementaryCharCategoryTable = new SupplementaryCharacterData(temp3);
431+
432+ /* Read additional data */
433+ if (additionalDataLength > 0) {
434+ additionalData = new byte[additionalDataLength];
435+ System.arraycopy(buffer, offset, additionalData, 0, additionalDataLength);
436+ }
437+
438+ /* Set numCategories */
439+ numCategories = stateTable.length / endStates.length;
440+ }
441+
442+ protected byte[] readFile(final String datafile)
443+ throws IOException, MissingResourceException {
444+
445+ BufferedInputStream is;
446+ try {
447+ is = (BufferedInputStream)AccessController.doPrivileged(
448+ new PrivilegedExceptionAction() {
449+ public Object run() throws Exception {
450+ return new BufferedInputStream(getClass().getResourceAsStream("/sun/text/resources/" + datafile));
451+ }
452+ }
453+ );
454+ }
455+ catch (PrivilegedActionException e) {
456+ throw new InternalError(e.toString());
457+ }
458+
459+ int offset = 0;
460+
461+ /* First, read magic, version, and header_info. */
462+ int len = LABEL_LENGTH + 5;
463+ byte[] buf = new byte[len];
464+ if (is.read(buf) != len) {
465+ throw new MissingResourceException("Wrong header length",
466+ datafile, "");
467+ }
468+
469+ /* Validate the magic number. */
470+ for (int i = 0; i < LABEL_LENGTH; i++, offset++) {
471+ if (buf[offset] != LABEL[offset]) {
472+ throw new MissingResourceException("Wrong magic number",
473+ datafile, "");
474+ }
475+ }
476+
477+ /* Validate the version number. */
478+ if (buf[offset] != supportedVersion) {
479+ throw new MissingResourceException("Unsupported version(" + buf[offset] + ")",
480+ datafile, "");
481+ }
482+
483+ /* Read data: totalDataSize + 8(for checksum) */
484+ len = BreakIterator.getInt(buf, ++offset);
485+ buf = new byte[len];
486+ if (is.read(buf) != len) {
487+ throw new MissingResourceException("Wrong data length",
488+ datafile, "");
489+ }
490+
491+ is.close();
492+
493+ return buf;
494+ }
495+
496+ byte[] getAdditionalData() {
497+ return additionalData;
498+ }
499+
500+ void setAdditionalData(byte[] b) {
501+ additionalData = b;
502+ }
503+
504+ //=======================================================================
505+ // boilerplate
506+ //=======================================================================
507+ /**
508+ * Clones this iterator.
509+ * @return A newly-constructed RuleBasedBreakIterator with the same
510+ * behavior as this one.
511+ */
512+ public Object clone() {
513+ RuleBasedBreakIterator result = (RuleBasedBreakIterator) super.clone();
514+ if (text != null) {
515+ result.text = (CharacterIterator) text.clone();
516+ }
517+ return result;
518+ }
519+
520+ /**
521+ * Returns true if both BreakIterators are of the same class, have the same
522+ * rules, and iterate over the same text.
523+ */
524+ public boolean equals(Object that) {
525+ try {
526+ if (that == null) {
527+ return false;
528+ }
529+
530+ RuleBasedBreakIterator other = (RuleBasedBreakIterator) that;
531+ if (checksum != other.checksum) {
532+ return false;
533+ }
534+ if (text == null) {
535+ return other.text == null;
536+ } else {
537+ return text.equals(other.text);
538+ }
539+ }
540+ catch(ClassCastException e) {
541+ return false;
542+ }
543+ }
544+
545+ /**
546+ * Returns text
547+ */
548+ public String toString() {
549+ StringBuffer sb = new StringBuffer();
550+ sb.append('[');
551+ sb.append("checksum=0x" + Long.toHexString(checksum));
552+ sb.append(']');
553+ return sb.toString();
554+ }
555+
556+ /**
557+ * Compute a hashcode for this BreakIterator
558+ * @return A hash code
559+ */
560+ public int hashCode() {
561+ return (int)checksum;
562+ }
563+
564+ //=======================================================================
565+ // BreakIterator overrides
566+ //=======================================================================
567+
568+ /**
569+ * Sets the current iteration position to the beginning of the text.
570+ * (i.e., the CharacterIterator's starting offset).
571+ * @return The offset of the beginning of the text.
572+ */
573+ public int first() {
574+ CharacterIterator t = getText();
575+
576+ t.first();
577+ return t.getIndex();
578+ }
579+
580+ /**
581+ * Sets the current iteration position to the end of the text.
582+ * (i.e., the CharacterIterator's ending offset).
583+ * @return The text's past-the-end offset.
584+ */
585+ public int last() {
586+ CharacterIterator t = getText();
587+
588+ // I'm not sure why, but t.last() returns the offset of the last character,
589+ // rather than the past-the-end offset
590+ t.setIndex(t.getEndIndex());
591+ return t.getIndex();
592+ }
593+
594+ /**
595+ * Advances the iterator either forward or backward the specified number of steps.
596+ * Negative values move backward, and positive values move forward. This is
597+ * equivalent to repeatedly calling next() or previous().
598+ * @param n The number of steps to move. The sign indicates the direction
599+ * (negative is backwards, and positive is forwards).
600+ * @return The character offset of the boundary position n boundaries away from
601+ * the current one.
602+ */
603+ public int next(int n) {
604+ int result = current();
605+ while (n > 0) {
606+ result = handleNext();
607+ --n;
608+ }
609+ while (n < 0) {
610+ result = previous();
611+ ++n;
612+ }
613+ return result;
614+ }
615+
616+ /**
617+ * Advances the iterator to the next boundary position.
618+ * @return The position of the first boundary after this one.
619+ */
620+ public int next() {
621+ return handleNext();
622+ }
623+
624+ private int cachedLastKnownBreak = BreakIterator.DONE;
625+
626+ /**
627+ * Advances the iterator backwards, to the last boundary preceding this one.
628+ * @return The position of the last boundary position preceding this one.
629+ */
630+ public int previous() {
631+ // if we're already sitting at the beginning of the text, return DONE
632+ CharacterIterator text = getText();
633+ if (current() == text.getBeginIndex()) {
634+ return BreakIterator.DONE;
635+ }
636+
637+ // set things up. handlePrevious() will back us up to some valid
638+ // break position before the current position (we back our internal
639+ // iterator up one step to prevent handlePrevious() from returning
640+ // the current position), but not necessarily the last one before
641+ // where we started
642+ int start = current();
643+ int lastResult = cachedLastKnownBreak;
644+ if (lastResult >= start || lastResult <= BreakIterator.DONE) {
645+ getPrevious();
646+ lastResult = handlePrevious();
647+ } else {
648+ //it might be better to check if handlePrevious() give us closer
649+ //safe value but handlePrevious() is slow too
650+ //So, this has to be done carefully
651+ text.setIndex(lastResult);
652+ }
653+ int result = lastResult;
654+
655+ // iterate forward from the known break position until we pass our
656+ // starting point. The last break position before the starting
657+ // point is our return value
658+ while (result != BreakIterator.DONE && result < start) {
659+ lastResult = result;
660+ result = handleNext();
661+ }
662+
663+ // set the current iteration position to be the last break position
664+ // before where we started, and then return that value
665+ text.setIndex(lastResult);
666+ cachedLastKnownBreak = lastResult;
667+ return lastResult;
668+ }
669+
670+ /**
671+ * Returns previous character
672+ */
673+ private int getPrevious() {
674+ char c2 = text.previous();
675+ if (Character.isLowSurrogate(c2) &&
676+ text.getIndex() > text.getBeginIndex()) {
677+ char c1 = text.previous();
678+ if (Character.isHighSurrogate(c1)) {
679+ return Character.toCodePoint(c1, c2);
680+ } else {
681+ text.next();
682+ }
683+ }
684+ return (int)c2;
685+ }
686+
687+ /**
688+ * Returns current character
689+ */
690+ int getCurrent() {
691+ char c1 = text.current();
692+ if (Character.isHighSurrogate(c1) &&
693+ text.getIndex() < text.getEndIndex()) {
694+ char c2 = text.next();
695+ text.previous();
696+ if (Character.isLowSurrogate(c2)) {
697+ return Character.toCodePoint(c1, c2);
698+ }
699+ }
700+ return (int)c1;
701+ }
702+
703+ /**
704+ * Returns the count of next character.
705+ */
706+ private int getCurrentCodePointCount() {
707+ char c1 = text.current();
708+ if (Character.isHighSurrogate(c1) &&
709+ text.getIndex() < text.getEndIndex()) {
710+ char c2 = text.next();
711+ text.previous();
712+ if (Character.isLowSurrogate(c2)) {
713+ return 2;
714+ }
715+ }
716+ return 1;
717+ }
718+
719+ /**
720+ * Returns next character
721+ */
722+ int getNext() {
723+ int index = text.getIndex();
724+ int endIndex = text.getEndIndex();
725+ if (index == endIndex ||
726+ (index = index + getCurrentCodePointCount()) >= endIndex) {
727+ return CharacterIterator.DONE;
728+ }
729+ text.setIndex(index);
730+ return getCurrent();
731+ }
732+
733+ /**
734+ * Returns the position of next character.
735+ */
736+ private int getNextIndex() {
737+ int index = text.getIndex() + getCurrentCodePointCount();
738+ int endIndex = text.getEndIndex();
739+ if (index > endIndex) {
740+ return endIndex;
741+ } else {
742+ return index;
743+ }
744+ }
745+
746+ /**
747+ * Throw IllegalArgumentException unless begin <= offset < end.
748+ */
749+ protected static final void checkOffset(int offset, CharacterIterator text) {
750+ if (offset < text.getBeginIndex() || offset > text.getEndIndex()) {
751+ throw new IllegalArgumentException("offset out of bounds");
752+ }
753+ }
754+
755+ /**
756+ * Sets the iterator to refer to the first boundary position following
757+ * the specified position.
758+ * @offset The position from which to begin searching for a break position.
759+ * @return The position of the first break after the current position.
760+ */
761+ public int following(int offset) {
762+
763+ CharacterIterator text = getText();
764+ checkOffset(offset, text);
765+
766+ // Set our internal iteration position (temporarily)
767+ // to the position passed in. If this is the _beginning_ position,
768+ // then we can just use next() to get our return value
769+ text.setIndex(offset);
770+ if (offset == text.getBeginIndex()) {
771+ cachedLastKnownBreak = handleNext();
772+ return cachedLastKnownBreak;
773+ }
774+
775+ // otherwise, we have to sync up first. Use handlePrevious() to back
776+ // us up to a known break position before the specified position (if
777+ // we can determine that the specified position is a break position,
778+ // we don't back up at all). This may or may not be the last break
779+ // position at or before our starting position. Advance forward
780+ // from here until we've passed the starting position. The position
781+ // we stop on will be the first break position after the specified one.
782+ int result = cachedLastKnownBreak;
783+ if (result >= offset || result <= BreakIterator.DONE) {
784+ result = handlePrevious();
785+ } else {
786+ //it might be better to check if handlePrevious() give us closer
787+ //safe value but handlePrevious() is slow too
788+ //So, this has to be done carefully
789+ text.setIndex(result);
790+ }
791+ while (result != BreakIterator.DONE && result <= offset) {
792+ result = handleNext();
793+ }
794+ cachedLastKnownBreak = result;
795+ return result;
796+ }
797+
798+ /**
799+ * Sets the iterator to refer to the last boundary position before the
800+ * specified position.
801+ * @offset The position to begin searching for a break from.
802+ * @return The position of the last boundary before the starting position.
803+ */
804+ public int preceding(int offset) {
805+ // if we start by updating the current iteration position to the
806+ // position specified by the caller, we can just use previous()
807+ // to carry out this operation
808+ CharacterIterator text = getText();
809+ checkOffset(offset, text);
810+ text.setIndex(offset);
811+ return previous();
812+ }
813+
814+ /**
815+ * Returns true if the specfied position is a boundary position. As a side
816+ * effect, leaves the iterator pointing to the first boundary position at
817+ * or after "offset".
818+ * @param offset the offset to check.
819+ * @return True if "offset" is a boundary position.
820+ */
821+ public boolean isBoundary(int offset) {
822+ CharacterIterator text = getText();
823+ checkOffset(offset, text);
824+ if (offset == text.getBeginIndex()) {
825+ return true;
826+ }
827+
828+ // to check whether this is a boundary, we can use following() on the
829+ // position before the specified one and return true if the position we
830+ // get back is the one the user specified
831+ else {
832+ return following(offset - 1) == offset;
833+ }
834+ }
835+
836+ /**
837+ * Returns the current iteration position.
838+ * @return The current iteration position.
839+ */
840+ public int current() {
841+ return getText().getIndex();
842+ }
843+
844+ /**
845+ * Return a CharacterIterator over the text being analyzed. This version
846+ * of this method returns the actual CharacterIterator we're using internally.
847+ * Changing the state of this iterator can have undefined consequences. If
848+ * you need to change it, clone it first.
849+ * @return An iterator over the text being analyzed.
850+ */
851+ public CharacterIterator getText() {
852+ // The iterator is initialized pointing to no text at all, so if this
853+ // function is called while we're in that state, we have to fudge an
854+ // iterator to return.
855+ if (text == null) {
856+ text = new StringCharacterIterator("");
857+ }
858+ return text;
859+ }
860+
861+ /**
862+ * Set the iterator to analyze a new piece of text. This function resets
863+ * the current iteration position to the beginning of the text.
864+ * @param newText An iterator over the text to analyze.
865+ */
866+ public void setText(CharacterIterator newText) {
867+ // Test iterator to see if we need to wrap it in a SafeCharIterator.
868+ // The correct behavior for CharacterIterators is to allow the
869+ // position to be set to the endpoint of the iterator. Many
870+ // CharacterIterators do not uphold this, so this is a workaround
871+ // to permit them to use this class.
872+ int end = newText.getEndIndex();
873+ boolean goodIterator;
874+ try {
875+ newText.setIndex(end); // some buggy iterators throw an exception here
876+ goodIterator = newText.getIndex() == end;
877+ }
878+ catch(IllegalArgumentException e) {
879+ goodIterator = false;
880+ }
881+
882+ if (goodIterator) {
883+ text = newText;
884+ }
885+ else {
886+ text = new SafeCharIterator(newText);
887+ }
888+ text.first();
889+
890+ cachedLastKnownBreak = BreakIterator.DONE;
891+ }
892+
893+
894+ //=======================================================================
895+ // implementation
896+ //=======================================================================
897+
898+ /**
899+ * This method is the actual implementation of the next() method. All iteration
900+ * vectors through here. This method initializes the state machine to state 1
901+ * and advances through the text character by character until we reach the end
902+ * of the text or the state machine transitions to state 0. We update our return
903+ * value every time the state machine passes through a possible end state.
904+ */
905+ protected int handleNext() {
906+ // if we're already at the end of the text, return DONE.
907+ CharacterIterator text = getText();
908+ if (text.getIndex() == text.getEndIndex()) {
909+ return BreakIterator.DONE;
910+ }
911+
912+ // no matter what, we always advance at least one character forward
913+ int result = getNextIndex();
914+ int lookaheadResult = 0;
915+
916+ // begin in state 1
917+ int state = START_STATE;
918+ int category;
919+ int c = getCurrent();
920+
921+ // loop until we reach the end of the text or transition to state 0
922+ while (c != CharacterIterator.DONE && state != STOP_STATE) {
923+
924+ // look up the current character's character category (which tells us
925+ // which column in the state table to look at)
926+ category = lookupCategory(c);
927+
928+ // if the character isn't an ignore character, look up a state
929+ // transition in the state table
930+ if (category != IGNORE) {
931+ state = lookupState(state, category);
932+ }
933+
934+ // if the state we've just transitioned to is a lookahead state,
935+ // (but not also an end state), save its position. If it's
936+ // both a lookahead state and an end state, update the break position
937+ // to the last saved lookup-state position
938+ if (lookaheadStates[state]) {
939+ if (endStates[state]) {
940+ result = lookaheadResult;
941+ }
942+ else {
943+ lookaheadResult = getNextIndex();
944+ }
945+ }
946+
947+ // otherwise, if the state we've just transitioned to is an accepting
948+ // state, update the break position to be the current iteration position
949+ else {
950+ if (endStates[state]) {
951+ result = getNextIndex();
952+ }
953+ }
954+
955+ c = getNext();
956+ }
957+
958+ // if we've run off the end of the text, and the very last character took us into
959+ // a lookahead state, advance the break position to the lookahead position
960+ // (the theory here is that if there are no characters at all after the lookahead
961+ // position, that always matches the lookahead criteria)
962+ if (c == CharacterIterator.DONE && lookaheadResult == text.getEndIndex()) {
963+ result = lookaheadResult;
964+ }
965+
966+ text.setIndex(result);
967+ return result;
968+ }
969+
970+ /**
971+ * This method backs the iterator back up to a "safe position" in the text.
972+ * This is a position that we know, without any context, must be a break position.
973+ * The various calling methods then iterate forward from this safe position to
974+ * the appropriate position to return. (For more information, see the description
975+ * of buildBackwardsStateTable() in RuleBasedBreakIterator.Builder.)
976+ */
977+ protected int handlePrevious() {
978+ CharacterIterator text = getText();
979+ int state = START_STATE;
980+ int category = 0;
981+ int lastCategory = 0;
982+ int c = getCurrent();
983+
984+ // loop until we reach the beginning of the text or transition to state 0
985+ while (c != CharacterIterator.DONE && state != STOP_STATE) {
986+
987+ // save the last character's category and look up the current
988+ // character's category
989+ lastCategory = category;
990+ category = lookupCategory(c);
991+
992+ // if the current character isn't an ignore character, look up a
993+ // state transition in the backwards state table
994+ if (category != IGNORE) {
995+ state = lookupBackwardState(state, category);
996+ }
997+
998+ // then advance one character backwards
999+ c = getPrevious();
1000+ }
1001+
1002+ // if we didn't march off the beginning of the text, we're either one or two
1003+ // positions away from the real break position. (One because of the call to
1004+ // previous() at the end of the loop above, and another because the character
1005+ // that takes us into the stop state will always be the character BEFORE
1006+ // the break position.)
1007+ if (c != CharacterIterator.DONE) {
1008+ if (lastCategory != IGNORE) {
1009+ getNext();
1010+ getNext();
1011+ }
1012+ else {
1013+ getNext();
1014+ }
1015+ }
1016+ return text.getIndex();
1017+ }
1018+
1019+ /**
1020+ * Looks up a character's category (i.e., its category for breaking purposes,
1021+ * not its Unicode category)
1022+ */
1023+ protected int lookupCategory(int c) {
1024+ if (c < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
1025+ return charCategoryTable.elementAt((char)c);
1026+ } else {
1027+ return supplementaryCharCategoryTable.getValue(c);
1028+ }
1029+ }
1030+
1031+ /**
1032+ * Given a current state and a character category, looks up the
1033+ * next state to transition to in the state table.
1034+ */
1035+ protected int lookupState(int state, int category) {
1036+ return stateTable[state * numCategories + category];
1037+ }
1038+
1039+ /**
1040+ * Given a current state and a character category, looks up the
1041+ * next state to transition to in the backwards state table.
1042+ */
1043+ protected int lookupBackwardState(int state, int category) {
1044+ return backwardsStateTable[state * numCategories + category];
1045+ }
1046+
1047+ /*
1048+ * This class exists to work around a bug in incorrect implementations
1049+ * of CharacterIterator, which incorrectly handle setIndex(endIndex).
1050+ * This iterator relies only on base.setIndex(n) where n is less than
1051+ * endIndex.
1052+ *
1053+ * One caveat: if the base iterator's begin and end indices change
1054+ * the change will not be reflected by this wrapper. Does that matter?
1055+ */
1056+ private static final class SafeCharIterator implements CharacterIterator,
1057+ Cloneable {
1058+
1059+ private CharacterIterator base;
1060+ private int rangeStart;
1061+ private int rangeLimit;
1062+ private int currentIndex;
1063+
1064+ SafeCharIterator(CharacterIterator base) {
1065+ this.base = base;
1066+ this.rangeStart = base.getBeginIndex();
1067+ this.rangeLimit = base.getEndIndex();
1068+ this.currentIndex = base.getIndex();
1069+ }
1070+
1071+ public char first() {
1072+ return setIndex(rangeStart);
1073+ }
1074+
1075+ public char last() {
1076+ return setIndex(rangeLimit - 1);
1077+ }
1078+
1079+ public char current() {
1080+ if (currentIndex < rangeStart || currentIndex >= rangeLimit) {
1081+ return DONE;
1082+ }
1083+ else {
1084+ return base.setIndex(currentIndex);
1085+ }
1086+ }
1087+
1088+ public char next() {
1089+
1090+ currentIndex++;
1091+ if (currentIndex >= rangeLimit) {
1092+ currentIndex = rangeLimit;
1093+ return DONE;
1094+ }
1095+ else {
1096+ return base.setIndex(currentIndex);
1097+ }
1098+ }
1099+
1100+ public char previous() {
1101+
1102+ currentIndex--;
1103+ if (currentIndex < rangeStart) {
1104+ currentIndex = rangeStart;
1105+ return DONE;
1106+ }
1107+ else {
1108+ return base.setIndex(currentIndex);
1109+ }
1110+ }
1111+
1112+ public char setIndex(int i) {
1113+
1114+ if (i < rangeStart || i > rangeLimit) {
1115+ throw new IllegalArgumentException("Invalid position");
1116+ }
1117+ currentIndex = i;
1118+ return current();
1119+ }
1120+
1121+ public int getBeginIndex() {
1122+ return rangeStart;
1123+ }
1124+
1125+ public int getEndIndex() {
1126+ return rangeLimit;
1127+ }
1128+
1129+ public int getIndex() {
1130+ return currentIndex;
1131+ }
1132+
1133+ public Object clone() {
1134+
1135+ SafeCharIterator copy = null;
1136+ try {
1137+ copy = (SafeCharIterator) super.clone();
1138+ }
1139+ catch(CloneNotSupportedException e) {
1140+ throw new Error("Clone not supported: " + e);
1141+ }
1142+
1143+ CharacterIterator copyOfBase = (CharacterIterator) base.clone();
1144+ copy.base = copyOfBase;
1145+ return copy;
1146+ }
1147+ }
1148+}
java/pkg/java/text/RuleBasedCollationKey.class+0−0

Binary file not shown.

java/pkg/java/text/RuleBasedCollationKey.java+123−0
@@ -0,0 +1,123 @@
1+/*
2+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+/**
42+ * A RuleBasedCollationKey is a concrete implementation of CollationKey class.
43+ * The RuleBasedCollationKey class is used by the RuleBasedCollator class.
44+ */
45+
46+final class RuleBasedCollationKey extends CollationKey {
47+ /**
48+ * Compare this RuleBasedCollationKey to target. The collation rules of the
49+ * Collator object which created these keys are applied. <strong>Note:</strong>
50+ * RuleBasedCollationKeys created by different Collators can not be compared.
51+ * @param target target RuleBasedCollationKey
52+ * @return Returns an integer value. Value is less than zero if this is less
53+ * than target, value is zero if this and target are equal and value is greater than
54+ * zero if this is greater than target.
55+ * @see java.text.Collator#compare
56+ */
57+ public int compareTo(CollationKey target)
58+ {
59+ int result = key.compareTo(((RuleBasedCollationKey)(target)).key);
60+ if (result <= Collator.LESS)
61+ return Collator.LESS;
62+ else if (result >= Collator.GREATER)
63+ return Collator.GREATER;
64+ return Collator.EQUAL;
65+ }
66+
67+ /**
68+ * Compare this RuleBasedCollationKey and the target for equality.
69+ * The collation rules of the Collator object which created these keys are applied.
70+ * <strong>Note:</strong> RuleBasedCollationKeys created by different Collators can not be
71+ * compared.
72+ * @param target the RuleBasedCollationKey to compare to.
73+ * @return Returns true if two objects are equal, false otherwise.
74+ */
75+ public boolean equals(Object target) {
76+ if (this == target) return true;
77+ if (target == null || !getClass().equals(target.getClass())) {
78+ return false;
79+ }
80+ RuleBasedCollationKey other = (RuleBasedCollationKey)target;
81+ return key.equals(other.key);
82+ }
83+
84+ /**
85+ * Creates a hash code for this RuleBasedCollationKey. The hash value is calculated on the
86+ * key itself, not the String from which the key was created. Thus
87+ * if x and y are RuleBasedCollationKeys, then x.hashCode(x) == y.hashCode() if
88+ * x.equals(y) is true. This allows language-sensitive comparison in a hash table.
89+ * See the CollatinKey class description for an example.
90+ * @return the hash value based on the string's collation order.
91+ */
92+ public int hashCode() {
93+ return (key.hashCode());
94+ }
95+
96+ /**
97+ * Converts the RuleBasedCollationKey to a sequence of bits. If two RuleBasedCollationKeys
98+ * could be legitimately compared, then one could compare the byte arrays
99+ * for each of those keys to obtain the same result. Byte arrays are
100+ * organized most significant byte first.
101+ */
102+ public byte[] toByteArray() {
103+
104+ char[] src = key.toCharArray();
105+ byte[] dest = new byte[ 2*src.length ];
106+ int j = 0;
107+ for( int i=0; i<src.length; i++ ) {
108+ dest[j++] = (byte)(src[i] >>> 8);
109+ dest[j++] = (byte)(src[i] & 0x00ff);
110+ }
111+ return dest;
112+ }
113+
114+ /**
115+ * A RuleBasedCollationKey can only be generated by Collator objects.
116+ */
117+ RuleBasedCollationKey(String source, String key) {
118+ super(source);
119+ this.key = key;
120+ }
121+ private String key = null;
122+
123+}
java/pkg/java/text/RuleBasedCollator.class+0−0

Binary file not shown.

java/pkg/java/text/RuleBasedCollator.java+763−0
@@ -0,0 +1,763 @@
1+/*
2+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+/*
27+ * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
28+ * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
29+ *
30+ * The original version of this source code and documentation is copyrighted
31+ * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
32+ * materials are provided under terms of a License Agreement between Taligent
33+ * and Sun. This technology is protected by multiple US and International
34+ * patents. This notice and attribution to Taligent may not be removed.
35+ * Taligent is a registered trademark of Taligent, Inc.
36+ *
37+ */
38+
39+package java.text;
40+
41+import java.text.Normalizer;
42+import java.util.Vector;
43+import java.util.Locale;
44+
45+/**
46+ * The <code>RuleBasedCollator</code> class is a concrete subclass of
47+ * <code>Collator</code> that provides a simple, data-driven, table
48+ * collator. With this class you can create a customized table-based
49+ * <code>Collator</code>. <code>RuleBasedCollator</code> maps
50+ * characters to sort keys.
51+ *
52+ * <p>
53+ * <code>RuleBasedCollator</code> has the following restrictions
54+ * for efficiency (other subclasses may be used for more complex languages) :
55+ * <ol>
56+ * <li>If a special collation rule controlled by a &lt;modifier&gt; is
57+ specified it applies to the whole collator object.
58+ * <li>All non-mentioned characters are at the end of the
59+ * collation order.
60+ * </ol>
61+ *
62+ * <p>
63+ * The collation table is composed of a list of collation rules, where each
64+ * rule is of one of three forms:
65+ * <pre>
66+ * &lt;modifier&gt;
67+ * &lt;relation&gt; &lt;text-argument&gt;
68+ * &lt;reset&gt; &lt;text-argument&gt;
69+ * </pre>
70+ * The definitions of the rule elements is as follows:
71+ * <UL Type=disc>
72+ * <LI><strong>Text-Argument</strong>: A text-argument is any sequence of
73+ * characters, excluding special characters (that is, common
74+ * whitespace characters [0009-000D, 0020] and rule syntax characters
75+ * [0021-002F, 003A-0040, 005B-0060, 007B-007E]). If those
76+ * characters are desired, you can put them in single quotes
77+ * (e.g. ampersand => '&'). Note that unquoted white space characters
78+ * are ignored; e.g. <code>b c</code> is treated as <code>bc</code>.
79+ * <LI><strong>Modifier</strong>: There are currently two modifiers that
80+ * turn on special collation rules.
81+ * <UL Type=square>
82+ * <LI>'@' : Turns on backwards sorting of accents (secondary
83+ * differences), as in French.
84+ * <LI>'!' : Turns on Thai/Lao vowel-consonant swapping. If this
85+ * rule is in force when a Thai vowel of the range
86+ * &#92;U0E40-&#92;U0E44 precedes a Thai consonant of the range
87+ * &#92;U0E01-&#92;U0E2E OR a Lao vowel of the range &#92;U0EC0-&#92;U0EC4
88+ * precedes a Lao consonant of the range &#92;U0E81-&#92;U0EAE then
89+ * the vowel is placed after the consonant for collation
90+ * purposes.
91+ * </UL>
92+ * <p>'@' : Indicates that accents are sorted backwards, as in French.
93+ * <LI><strong>Relation</strong>: The relations are the following:
94+ * <UL Type=square>
95+ * <LI>'&lt;' : Greater, as a letter difference (primary)
96+ * <LI>';' : Greater, as an accent difference (secondary)
97+ * <LI>',' : Greater, as a case difference (tertiary)
98+ * <LI>'=' : Equal
99+ * </UL>
100+ * <LI><strong>Reset</strong>: There is a single reset
101+ * which is used primarily for contractions and expansions, but which
102+ * can also be used to add a modification at the end of a set of rules.
103+ * <p>'&' : Indicates that the next rule follows the position to where
104+ * the reset text-argument would be sorted.
105+ * </UL>
106+ *
107+ * <p>
108+ * This sounds more complicated than it is in practice. For example, the
109+ * following are equivalent ways of expressing the same thing:
110+ * <blockquote>
111+ * <pre>
112+ * a &lt; b &lt; c
113+ * a &lt; b &amp; b &lt; c
114+ * a &lt; c &amp; a &lt; b
115+ * </pre>
116+ * </blockquote>
117+ * Notice that the order is important, as the subsequent item goes immediately
118+ * after the text-argument. The following are not equivalent:
119+ * <blockquote>
120+ * <pre>
121+ * a &lt; b &amp; a &lt; c
122+ * a &lt; c &amp; a &lt; b
123+ * </pre>
124+ * </blockquote>
125+ * Either the text-argument must already be present in the sequence, or some
126+ * initial substring of the text-argument must be present. (e.g. "a &lt; b &amp; ae &lt;
127+ * e" is valid since "a" is present in the sequence before "ae" is reset). In
128+ * this latter case, "ae" is not entered and treated as a single character;
129+ * instead, "e" is sorted as if it were expanded to two characters: "a"
130+ * followed by an "e". This difference appears in natural languages: in
131+ * traditional Spanish "ch" is treated as though it contracts to a single
132+ * character (expressed as "c &lt; ch &lt; d"), while in traditional German
133+ * a-umlaut is treated as though it expanded to two characters
134+ * (expressed as "a,A &lt; b,B ... &amp;ae;&#92;u00e3&amp;AE;&#92;u00c3").
135+ * [&#92;u00e3 and &#92;u00c3 are, of course, the escape sequences for a-umlaut.]
136+ * <p>
137+ * <strong>Ignorable Characters</strong>
138+ * <p>
139+ * For ignorable characters, the first rule must start with a relation (the
140+ * examples we have used above are really fragments; "a &lt; b" really should be
141+ * "&lt; a &lt; b"). If, however, the first relation is not "&lt;", then all the all
142+ * text-arguments up to the first "&lt;" are ignorable. For example, ", - &lt; a &lt; b"
143+ * makes "-" an ignorable character, as we saw earlier in the word
144+ * "black-birds". In the samples for different languages, you see that most
145+ * accents are ignorable.
146+ *
147+ * <p><strong>Normalization and Accents</strong>
148+ * <p>
149+ * <code>RuleBasedCollator</code> automatically processes its rule table to
150+ * include both pre-composed and combining-character versions of
151+ * accented characters. Even if the provided rule string contains only
152+ * base characters and separate combining accent characters, the pre-composed
153+ * accented characters matching all canonical combinations of characters from
154+ * the rule string will be entered in the table.
155+ * <p>
156+ * This allows you to use a RuleBasedCollator to compare accented strings
157+ * even when the collator is set to NO_DECOMPOSITION. There are two caveats,
158+ * however. First, if the strings to be collated contain combining
159+ * sequences that may not be in canonical order, you should set the collator to
160+ * CANONICAL_DECOMPOSITION or FULL_DECOMPOSITION to enable sorting of
161+ * combining sequences. Second, if the strings contain characters with
162+ * compatibility decompositions (such as full-width and half-width forms),
163+ * you must use FULL_DECOMPOSITION, since the rule tables only include
164+ * canonical mappings.
165+ *
166+ * <p><strong>Errors</strong>
167+ * <p>
168+ * The following are errors:
169+ * <UL Type=disc>
170+ * <LI>A text-argument contains unquoted punctuation symbols
171+ * (e.g. "a &lt; b-c &lt; d").
172+ * <LI>A relation or reset character not followed by a text-argument
173+ * (e.g. "a &lt; ,b").
174+ * <LI>A reset where the text-argument (or an initial substring of the
175+ * text-argument) is not already in the sequence.
176+ * (e.g. "a &lt; b &amp; e &lt; f")
177+ * </UL>
178+ * If you produce one of these errors, a <code>RuleBasedCollator</code> throws
179+ * a <code>ParseException</code>.
180+ *
181+ * <p><strong>Examples</strong>
182+ * <p>Simple: "&lt; a &lt; b &lt; c &lt; d"
183+ * <p>Norwegian: "&lt; a, A &lt; b, B &lt; c, C &lt; d, D &lt; e, E &lt; f, F
184+ * &lt; g, G &lt; h, H &lt; i, I &lt; j, J &lt; k, K &lt; l, L
185+ * &lt; m, M &lt; n, N &lt; o, O &lt; p, P &lt; q, Q &lt; r, R
186+ * &lt; s, S &lt; t, T &lt; u, U &lt; v, V &lt; w, W &lt; x, X
187+ * &lt; y, Y &lt; z, Z
188+ * &lt; &#92;u00E6, &#92;u00C6
189+ * &lt; &#92;u00F8, &#92;u00D8
190+ * &lt; &#92;u00E5 = a&#92;u030A, &#92;u00C5 = A&#92;u030A;
191+ * aa, AA"
192+ *
193+ * <p>
194+ * To create a <code>RuleBasedCollator</code> object with specialized
195+ * rules tailored to your needs, you construct the <code>RuleBasedCollator</code>
196+ * with the rules contained in a <code>String</code> object. For example:
197+ * <blockquote>
198+ * <pre>
199+ * String simple = "&lt; a&lt; b&lt; c&lt; d";
200+ * RuleBasedCollator mySimple = new RuleBasedCollator(simple);
201+ * </pre>
202+ * </blockquote>
203+ * Or:
204+ * <blockquote>
205+ * <pre>
206+ * String Norwegian = "&lt; a, A &lt; b, B &lt; c, C &lt; d, D &lt; e, E &lt; f, F &lt; g, G &lt; h, H &lt; i, I" +
207+ * "&lt; j, J &lt; k, K &lt; l, L &lt; m, M &lt; n, N &lt; o, O &lt; p, P &lt; q, Q &lt; r, R" +
208+ * "&lt; s, S &lt; t, T &lt; u, U &lt; v, V &lt; w, W &lt; x, X &lt; y, Y &lt; z, Z" +
209+ * "&lt; &#92;u00E6, &#92;u00C6" + // Latin letter ae & AE
210+ * "&lt; &#92;u00F8, &#92;u00D8" + // Latin letter o & O with stroke
211+ * "&lt; &#92;u00E5 = a&#92;u030A," + // Latin letter a with ring above
212+ * " &#92;u00C5 = A&#92;u030A;" + // Latin letter A with ring above
213+ * " aa, AA";
214+ * RuleBasedCollator myNorwegian = new RuleBasedCollator(Norwegian);
215+ * </pre>
216+ * </blockquote>
217+ *
218+ * <p>
219+ * A new collation rules string can be created by concatenating rules
220+ * strings. For example, the rules returned by {@link #getRules()} could
221+ * be concatenated to combine multiple <code>RuleBasedCollator</code>s.
222+ *
223+ * <p>
224+ * The following example demonstrates how to change the order of
225+ * non-spacing accents,
226+ * <blockquote>
227+ * <pre>
228+ * // old rule
229+ * String oldRules = "=&#92;u0301;&#92;u0300;&#92;u0302;&#92;u0308" // main accents
230+ * + ";&#92;u0327;&#92;u0303;&#92;u0304;&#92;u0305" // main accents
231+ * + ";&#92;u0306;&#92;u0307;&#92;u0309;&#92;u030A" // main accents
232+ * + ";&#92;u030B;&#92;u030C;&#92;u030D;&#92;u030E" // main accents
233+ * + ";&#92;u030F;&#92;u0310;&#92;u0311;&#92;u0312" // main accents
234+ * + "&lt; a , A ; ae, AE ; &#92;u00e6 , &#92;u00c6"
235+ * + "&lt; b , B &lt; c, C &lt; e, E & C &lt; d, D";
236+ * // change the order of accent characters
237+ * String addOn = "& &#92;u0300 ; &#92;u0308 ; &#92;u0302";
238+ * RuleBasedCollator myCollator = new RuleBasedCollator(oldRules + addOn);
239+ * </pre>
240+ * </blockquote>
241+ *
242+ * @see Collator
243+ * @see CollationElementIterator
244+ * @author Helena Shih, Laura Werner, Richard Gillam
245+ */
246+public class RuleBasedCollator extends Collator{
247+ // IMPLEMENTATION NOTES: The implementation of the collation algorithm is
248+ // divided across three classes: RuleBasedCollator, RBCollationTables, and
249+ // CollationElementIterator. RuleBasedCollator contains the collator's
250+ // transient state and includes the code that uses the other classes to
251+ // implement comparison and sort-key building. RuleBasedCollator also
252+ // contains the logic to handle French secondary accent sorting.
253+ // A RuleBasedCollator has two CollationElementIterators. State doesn't
254+ // need to be preserved in these objects between calls to compare() or
255+ // getCollationKey(), but the objects persist anyway to avoid wasting extra
256+ // creation time. compare() and getCollationKey() are synchronized to ensure
257+ // thread safety with this scheme. The CollationElementIterator is responsible
258+ // for generating collation elements from strings and returning one element at
259+ // a time (sometimes there's a one-to-many or many-to-one mapping between
260+ // characters and collation elements-- this class handles that).
261+ // CollationElementIterator depends on RBCollationTables, which contains the
262+ // collator's static state. RBCollationTables contains the actual data
263+ // tables specifying the collation order of characters for a particular locale
264+ // or use. It also contains the base logic that CollationElementIterator
265+ // uses to map from characters to collation elements. A single RBCollationTables
266+ // object is shared among all RuleBasedCollators for the same locale, and
267+ // thus by all the CollationElementIterators they create.
268+
269+ /**
270+ * RuleBasedCollator constructor. This takes the table rules and builds
271+ * a collation table out of them. Please see RuleBasedCollator class
272+ * description for more details on the collation rule syntax.
273+ * @see java.util.Locale
274+ * @param rules the collation rules to build the collation table from.
275+ * @exception ParseException A format exception
276+ * will be thrown if the build process of the rules fails. For
277+ * example, build rule "a < ? < d" will cause the constructor to
278+ * throw the ParseException because the '?' is not quoted.
279+ */
280+ public RuleBasedCollator(String rules) throws ParseException {
281+ this(rules, Collator.CANONICAL_DECOMPOSITION);

482 more lines aren’t shown here.

java/pkg/java/text/SimpleDateFormat.class+0−0

Binary file not shown.

java/pkg/java/text/SimpleDateFormat.java+2350−0

This diff is large: its 2351 lines aren’t shown here.

java/pkg/java/text/StringCharacterIterator.class+0−0

Binary file not shown.

java/pkg/java/text/StringCharacterIterator.java+279−0

This diff is large: its 280 lines aren’t shown here.

java/pkg/java/text/mkfile+49−0

This diff is large: its 50 lines aren’t shown here.

java/pkg/java/text/package.html+65−0

This diff is large: its 66 lines aren’t shown here.

java/pkg/java/text/spi/BreakIteratorProvider.class+0−0

Binary file not shown.

java/pkg/java/text/spi/BreakIteratorProvider.java+107−0

This diff is large: its 108 lines aren’t shown here.

java/pkg/java/text/spi/CollatorProvider.class+0−0

Binary file not shown.

java/pkg/java/text/spi/CollatorProvider.java+61−0

This diff is large: its 62 lines aren’t shown here.

java/pkg/java/text/spi/DateFormatProvider.class+0−0

Binary file not shown.

java/pkg/java/text/spi/DateFormatProvider.java+114−0

This diff is large: its 115 lines aren’t shown here.

java/pkg/java/text/spi/DateFormatSymbolsProvider.class+0−0

Binary file not shown.

java/pkg/java/text/spi/DateFormatSymbolsProvider.java+62−0

This diff is large: its 63 lines aren’t shown here.

java/pkg/java/text/spi/DecimalFormatSymbolsProvider.class+0−0

Binary file not shown.

java/pkg/java/text/spi/DecimalFormatSymbolsProvider.java+62−0

This diff is large: its 63 lines aren’t shown here.

java/pkg/java/text/spi/NumberFormatProvider.class+0−0

Binary file not shown.

java/pkg/java/text/spi/NumberFormatProvider.java+113−0

This diff is large: its 114 lines aren’t shown here.

java/pkg/java/text/spi/mkfile+13−0

This diff is large: its 14 lines aren’t shown here.

java/pkg/java/text/spi/package.html+50−0

This diff is large: its 51 lines aren’t shown here.