Adds formatting classes from the java.text package

This commit is contained in:
konsoletyper 2014-05-16 17:46:26 +04:00
parent 0cd1ddedc5
commit 2e97872496
16 changed files with 3284 additions and 17 deletions

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
public class Annotation {
private Object value;
public Annotation(Object attribute) {
value = attribute;
}
public Object getValue() {
return value;
}
@Override
public String toString() {
return getClass().getName() + "[value=" + value + ']';
}
}

View File

@ -0,0 +1,144 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.util.TMap;
import org.teavm.classlib.java.util.TSet;
public interface AttributedCharacterIterator extends CharacterIterator {
public static class Attribute implements TSerializable {
public static final Attribute INPUT_METHOD_SEGMENT = new Attribute(
"input_method_segment");
public static final Attribute LANGUAGE = new Attribute("language");
public static final Attribute READING = new Attribute("reading");
private String name;
protected Attribute(String name) {
this.name = name;
}
@Override
public final boolean equals(Object object) {
return this == object;
}
protected String getName() {
return name;
}
@Override
public final int hashCode() {
return super.hashCode();
}
@Override
public String toString() {
return getClass().getName() + '(' + getName() + ')';
}
}
/**
* Returns a set of attributes present in the {@code
* AttributedCharacterIterator}. An empty set is returned if no attributes
* were defined.
*
* @return a set of attribute keys; may be empty.
*/
public TSet<Attribute> getAllAttributeKeys();
/**
* Returns the value stored in the attribute for the current character. If
* the attribute was not defined then {@code null} is returned.
*
* @param attribute the attribute for which the value should be returned.
* @return the value of the requested attribute for the current character or
* {@code null} if it was not defined.
*/
public Object getAttribute(Attribute attribute);
/**
* Returns a map of all attributes of the current character. If no
* attributes were defined for the current character then an empty map is
* returned.
*
* @return a map of all attributes for the current character or an empty
* map.
*/
public TMap<Attribute, Object> getAttributes();
/**
* Returns the index of the last character in the run having the same
* attributes as the current character.
*
* @return the index of the last character of the current run.
*/
public int getRunLimit();
/**
* Returns the index of the last character in the run that has the same
* attribute value for the given attribute as the current character.
*
* @param attribute
* the attribute which the run is based on.
* @return the index of the last character of the current run.
*/
public int getRunLimit(Attribute attribute);
/**
* Returns the index of the last character in the run that has the same
* attribute values for the attributes in the set as the current character.
*
* @param attributes
* the set of attributes which the run is based on.
* @return the index of the last character of the current run.
*/
public int getRunLimit(TSet<? extends Attribute> attributes);
/**
* Returns the index of the first character in the run that has the same
* attributes as the current character.
*
* @return the index of the last character of the current run.
*/
public int getRunStart();
/**
* Returns the index of the first character in the run that has the same
* attribute value for the given attribute as the current character.
*
* @param attribute
* the attribute which the run is based on.
* @return the index of the last character of the current run.
*/
public int getRunStart(Attribute attribute);
/**
* Returns the index of the first character in the run that has the same
* attribute values for the attributes in the set as the current character.
*
* @param attributes
* the set of attributes which the run is based on.
* @return the index of the last character of the current run.
*/
public int getRunStart(TSet<? extends Attribute> attributes);
}

View File

@ -0,0 +1,630 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.text.AttributedCharacterIterator.Attribute;
import org.teavm.classlib.java.util.*;
public class AttributedString {
String text;
TMap<AttributedCharacterIterator.Attribute, TList<Range>> attributeMap;
static class Range {
int start;
int end;
Object value;
Range(int s, int e, Object v) {
start = s;
end = e;
value = v;
}
}
static class AttributedIterator implements AttributedCharacterIterator {
private int begin, end, offset;
private AttributedString attrString;
private THashSet<Attribute> attributesAllowed;
AttributedIterator(AttributedString attrString) {
this.attrString = attrString;
begin = 0;
end = attrString.text.length();
offset = 0;
}
AttributedIterator(AttributedString attrString, AttributedCharacterIterator.Attribute[] attributes, int begin,
int end) {
if (begin < 0 || end > attrString.text.length() || begin > end) {
throw new IllegalArgumentException();
}
this.begin = begin;
this.end = end;
offset = begin;
this.attrString = attrString;
if (attributes != null) {
THashSet<Attribute> set = new THashSet<>((attributes.length * 4 / 3) + 1);
for (int i = attributes.length; --i >= 0;) {
set.add(attributes[i]);
}
attributesAllowed = set;
}
}
@Override
@SuppressWarnings("unchecked")
public Object clone() {
try {
AttributedIterator clone = (AttributedIterator) super.clone();
if (attributesAllowed != null) {
clone.attributesAllowed = (THashSet<Attribute>) attributesAllowed.clone();
}
return clone;
} catch (CloneNotSupportedException e) {
return null;
}
}
@Override
public char current() {
if (offset == end) {
return DONE;
}
return attrString.text.charAt(offset);
}
@Override
public char first() {
if (begin == end) {
return DONE;
}
offset = begin;
return attrString.text.charAt(offset);
}
@Override
public int getBeginIndex() {
return begin;
}
@Override
public int getEndIndex() {
return end;
}
@Override
public int getIndex() {
return offset;
}
private boolean inRange(Range range) {
if (!(range.value instanceof Annotation)) {
return true;
}
return range.start >= begin && range.start < end && range.end > begin && range.end <= end;
}
private boolean inRange(TList<Range> ranges) {
TIterator<Range> it = ranges.iterator();
while (it.hasNext()) {
Range range = it.next();
if (range.start >= begin && range.start < end) {
return !(range.value instanceof Annotation) || (range.end > begin && range.end <= end);
} else if (range.end > begin && range.end <= end) {
return !(range.value instanceof Annotation) || (range.start >= begin && range.start < end);
}
}
return false;
}
@Override
public TSet<AttributedIterator.Attribute> getAllAttributeKeys() {
if (begin == 0 && end == attrString.text.length() && attributesAllowed == null) {
return attrString.attributeMap.keySet();
}
TSet<AttributedIterator.Attribute> result = new THashSet<>((attrString.attributeMap.size() * 4 / 3) + 1);
TIterator<TMap.Entry<Attribute, TList<Range>>> it = attrString.attributeMap.entrySet().iterator();
while (it.hasNext()) {
TMap.Entry<Attribute, TList<Range>> entry = it.next();
if (attributesAllowed == null || attributesAllowed.contains(entry.getKey())) {
TList<Range> ranges = entry.getValue();
if (inRange(ranges)) {
result.add(entry.getKey());
}
}
}
return result;
}
private Object currentValue(TList<Range> ranges) {
TIterator<Range> it = ranges.iterator();
while (it.hasNext()) {
Range range = it.next();
if (offset >= range.start && offset < range.end) {
return inRange(range) ? range.value : null;
}
}
return null;
}
@Override
public Object getAttribute(AttributedCharacterIterator.Attribute attribute) {
if (attributesAllowed != null && !attributesAllowed.contains(attribute)) {
return null;
}
TArrayList<Range> ranges = (TArrayList<Range>) attrString.attributeMap.get(attribute);
if (ranges == null) {
return null;
}
return currentValue(ranges);
}
@Override
public TMap<Attribute, Object> getAttributes() {
TMap<Attribute, Object> result = new THashMap<>((attrString.attributeMap.size() * 4 / 3) + 1);
TIterator<TMap.Entry<Attribute, TList<Range>>> it = attrString.attributeMap.entrySet().iterator();
while (it.hasNext()) {
TMap.Entry<Attribute, TList<Range>> entry = it.next();
if (attributesAllowed == null || attributesAllowed.contains(entry.getKey())) {
Object value = currentValue(entry.getValue());
if (value != null) {
result.put(entry.getKey(), value);
}
}
}
return result;
}
@Override
public int getRunLimit() {
return getRunLimit(getAllAttributeKeys());
}
private int runLimit(TList<Range> ranges) {
int result = end;
TListIterator<Range> it = ranges.listIterator(ranges.size());
while (it.hasPrevious()) {
Range range = it.previous();
if (range.end <= begin) {
break;
}
if (offset >= range.start && offset < range.end) {
return inRange(range) ? range.end : result;
} else if (offset >= range.end) {
break;
}
result = range.start;
}
return result;
}
@Override
public int getRunLimit(AttributedCharacterIterator.Attribute attribute) {
if (attributesAllowed != null && !attributesAllowed.contains(attribute)) {
return end;
}
TArrayList<Range> ranges = (TArrayList<Range>) attrString.attributeMap.get(attribute);
if (ranges == null) {
return end;
}
return runLimit(ranges);
}
@Override
public int getRunLimit(TSet<? extends Attribute> attributes) {
int limit = end;
TIterator<? extends Attribute> it = attributes.iterator();
while (it.hasNext()) {
AttributedCharacterIterator.Attribute attribute = it.next();
int newLimit = getRunLimit(attribute);
if (newLimit < limit) {
limit = newLimit;
}
}
return limit;
}
@Override
public int getRunStart() {
return getRunStart(getAllAttributeKeys());
}
private int runStart(TList<Range> ranges) {
int result = begin;
TIterator<Range> it = ranges.iterator();
while (it.hasNext()) {
Range range = it.next();
if (range.start >= end) {
break;
}
if (offset >= range.start && offset < range.end) {
return inRange(range) ? range.start : result;
} else if (offset < range.start) {
break;
}
result = range.end;
}
return result;
}
@Override
public int getRunStart(AttributedCharacterIterator.Attribute attribute) {
if (attributesAllowed != null && !attributesAllowed.contains(attribute)) {
return begin;
}
TArrayList<Range> ranges = (TArrayList<Range>) attrString.attributeMap.get(attribute);
if (ranges == null) {
return begin;
}
return runStart(ranges);
}
@Override
public int getRunStart(TSet<? extends Attribute> attributes) {
int start = begin;
TIterator<? extends Attribute> it = attributes.iterator();
while (it.hasNext()) {
AttributedCharacterIterator.Attribute attribute = it.next();
int newStart = getRunStart(attribute);
if (newStart > start) {
start = newStart;
}
}
return start;
}
@Override
public char last() {
if (begin == end) {
return DONE;
}
offset = end - 1;
return attrString.text.charAt(offset);
}
@Override
public char next() {
if (offset >= (end - 1)) {
offset = end;
return DONE;
}
return attrString.text.charAt(++offset);
}
@Override
public char previous() {
if (offset == begin) {
return DONE;
}
return attrString.text.charAt(--offset);
}
@Override
public char setIndex(int location) {
if (location < begin || location > end) {
throw new IllegalArgumentException();
}
offset = location;
if (offset == end) {
return DONE;
}
return attrString.text.charAt(offset);
}
}
public AttributedString(AttributedCharacterIterator iterator) {
if (iterator.getBeginIndex() > iterator.getEndIndex()) {
throw new IllegalArgumentException("Invalid substring range");
}
StringBuilder buffer = new StringBuilder();
for (int i = iterator.getBeginIndex(); i < iterator.getEndIndex(); i++) {
buffer.append(iterator.current());
iterator.next();
}
text = buffer.toString();
TSet<AttributedCharacterIterator.Attribute> attributes = iterator.getAllAttributeKeys();
if (attributes == null) {
return;
}
attributeMap = new THashMap<>((attributes.size() * 4 / 3) + 1);
TIterator<Attribute> it = attributes.iterator();
while (it.hasNext()) {
AttributedCharacterIterator.Attribute attribute = it.next();
iterator.setIndex(0);
while (iterator.current() != CharacterIterator.DONE) {
int start = iterator.getRunStart(attribute);
int limit = iterator.getRunLimit(attribute);
Object value = iterator.getAttribute(attribute);
if (value != null) {
addAttribute(attribute, value, start, limit);
}
iterator.setIndex(limit);
}
}
}
private AttributedString(AttributedCharacterIterator iterator, int start, int end, TSet<Attribute> attributes) {
if (start < iterator.getBeginIndex() || end > iterator.getEndIndex() || start > end) {
throw new IllegalArgumentException();
}
if (attributes == null) {
return;
}
StringBuilder buffer = new StringBuilder();
iterator.setIndex(start);
while (iterator.getIndex() < end) {
buffer.append(iterator.current());
iterator.next();
}
text = buffer.toString();
attributeMap = new THashMap<>((attributes.size() * 4 / 3) + 1);
TIterator<Attribute> it = attributes.iterator();
while (it.hasNext()) {
AttributedCharacterIterator.Attribute attribute = it.next();
iterator.setIndex(start);
while (iterator.getIndex() < end) {
Object value = iterator.getAttribute(attribute);
int runStart = iterator.getRunStart(attribute);
int limit = iterator.getRunLimit(attribute);
if ((value instanceof Annotation && runStart >= start && limit <= end) ||
(value != null && !(value instanceof Annotation))) {
addAttribute(attribute, value, (runStart < start ? start : runStart) - start, (limit > end ? end
: limit) - start);
}
iterator.setIndex(limit);
}
}
}
public AttributedString(AttributedCharacterIterator iterator, int start, int end) {
this(iterator, start, end, iterator.getAllAttributeKeys());
}
public AttributedString(AttributedCharacterIterator iterator, int start, int end,
AttributedCharacterIterator.Attribute[] attributes) {
this(iterator, start, end, new THashSet<>(TArrays.asList(attributes)));
}
public AttributedString(String value) {
if (value == null) {
throw new NullPointerException();
}
text = value;
attributeMap = new THashMap<>(11);
}
public AttributedString(String value, TMap<? extends AttributedCharacterIterator.Attribute, ?> attributes) {
if (value == null) {
throw new NullPointerException();
}
if (value.length() == 0 && !attributes.isEmpty()) {
throw new IllegalArgumentException("Cannot add attributes to empty string");
}
text = value;
attributeMap = new THashMap<>((attributes.size() * 4 / 3) + 1);
TIterator<?> it = attributes.entrySet().iterator();
while (it.hasNext()) {
TMap.Entry<?, ?> entry = (TMap.Entry<?, ?>) it.next();
TArrayList<Range> ranges = new TArrayList<>(1);
ranges.add(new Range(0, text.length(), entry.getValue()));
attributeMap.put((AttributedCharacterIterator.Attribute) entry.getKey(), ranges);
}
}
/**
* Applies a given attribute to this string.
*
* @param attribute
* the attribute that will be applied to this string.
* @param value
* the value of the attribute that will be applied to this
* string.
* @throws IllegalArgumentException
* if the length of this attributed string is 0.
* @throws NullPointerException
* if {@code attribute} is {@code null}.
*/
public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value) {
if (null == attribute) {
throw new NullPointerException();
}
if (text.length() == 0) {
throw new IllegalArgumentException();
}
TList<Range> ranges = attributeMap.get(attribute);
if (ranges == null) {
ranges = new TArrayList<Range>(1);
attributeMap.put(attribute, ranges);
} else {
ranges.clear();
}
ranges.add(new Range(0, text.length(), value));
}
/**
* Applies a given attribute to the given range of this string.
*
* @param attribute
* the attribute that will be applied to this string.
* @param value
* the value of the attribute that will be applied to this
* string.
* @param start
* the start of the range where the attribute will be applied.
* @param end
* the end of the range where the attribute will be applied.
* @throws IllegalArgumentException
* if {@code start < 0}, {@code end} is greater than the length
* of this string, or if {@code start >= end}.
* @throws NullPointerException
* if {@code attribute} is {@code null}.
*/
public void addAttribute(AttributedCharacterIterator.Attribute attribute, Object value, int start, int end) {
if (null == attribute) {
throw new NullPointerException();
}
if (start < 0 || end > text.length() || start >= end) {
throw new IllegalArgumentException();
}
if (value == null) {
return;
}
TList<Range> ranges = attributeMap.get(attribute);
if (ranges == null) {
ranges = new TArrayList<>(1);
ranges.add(new Range(start, end, value));
attributeMap.put(attribute, ranges);
return;
}
TListIterator<Range> it = ranges.listIterator();
while (it.hasNext()) {
Range range = it.next();
if (end <= range.start) {
it.previous();
break;
} else if (start < range.end || (start == range.end && value.equals(range.value))) {
Range r1 = null, r3;
it.remove();
r1 = new Range(range.start, start, range.value);
r3 = new Range(end, range.end, range.value);
while (end > range.end && it.hasNext()) {
range = it.next();
if (end <= range.end) {
if (end > range.start || (end == range.start && value.equals(range.value))) {
it.remove();
r3 = new Range(end, range.end, range.value);
break;
}
} else {
it.remove();
}
}
if (value.equals(r1.value)) {
if (value.equals(r3.value)) {
it.add(new Range(r1.start < start ? r1.start : start, r3.end > end ? r3.end : end, r1.value));
} else {
it.add(new Range(r1.start < start ? r1.start : start, end, r1.value));
if (r3.start < r3.end) {
it.add(r3);
}
}
} else {
if (value.equals(r3.value)) {
if (r1.start < r1.end) {
it.add(r1);
}
it.add(new Range(start, r3.end > end ? r3.end : end, r3.value));
} else {
if (r1.start < r1.end) {
it.add(r1);
}
it.add(new Range(start, end, value));
if (r3.start < r3.end) {
it.add(r3);
}
}
}
return;
}
}
it.add(new Range(start, end, value));
}
/**
* Applies a given set of attributes to the given range of the string.
*
* @param attributes
* the set of attributes that will be applied to this string.
* @param start
* the start of the range where the attribute will be applied.
* @param end
* the end of the range where the attribute will be applied.
* @throws IllegalArgumentException
* if {@code start < 0}, {@code end} is greater than the length
* of this string, or if {@code start >= end}.
*/
public void addAttributes(TMap<? extends AttributedCharacterIterator.Attribute, ?> attributes, int start, int end) {
TIterator<?> it = attributes.entrySet().iterator();
while (it.hasNext()) {
TMap.Entry<?, ?> entry = (TMap.Entry<?, ?>) it.next();
addAttribute((AttributedCharacterIterator.Attribute) entry.getKey(), entry.getValue(), start, end);
}
}
/**
* Returns an {@code AttributedCharacterIterator} that gives access to the
* complete content of this attributed string.
*
* @return the newly created {@code AttributedCharacterIterator}.
*/
public AttributedCharacterIterator getIterator() {
return new AttributedIterator(this);
}
/**
* Returns an {@code AttributedCharacterIterator} that gives access to the
* complete content of this attributed string. Only attributes contained in
* {@code attributes} are available from this iterator if they are defined
* for this text.
*
* @param attributes
* the array containing attributes that will be in the new
* iterator if they are defined for this text.
* @return the newly created {@code AttributedCharacterIterator}.
*/
public AttributedCharacterIterator getIterator(AttributedCharacterIterator.Attribute[] attributes) {
return new AttributedIterator(this, attributes, 0, text.length());
}
/**
* Returns an {@code AttributedCharacterIterator} that gives access to the
* contents of this attributed string starting at index {@code start} up to
* index {@code end}. Only attributes contained in {@code attributes} are
* available from this iterator if they are defined for this text.
*
* @param attributes
* the array containing attributes that will be in the new
* iterator if they are defined for this text.
* @param start
* the start index of the iterator on the underlying text.
* @param end
* the end index of the iterator on the underlying text.
* @return the newly created {@code AttributedCharacterIterator}.
*/
public AttributedCharacterIterator getIterator(AttributedCharacterIterator.Attribute[] attributes, int start,
int end) {
return new AttributedIterator(this, attributes, start, end);
}
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
public interface CharacterIterator extends Cloneable {
public static final char DONE = '\uffff';
public Object clone();
public char current();
public char first();
public int getBeginIndex();
public int getEndIndex();
public int getIndex();
public char last();
public char next();
public char previous();
public char setIndex(int location);
}

View File

@ -0,0 +1,280 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.util.*;
public abstract class DateFormat extends Format {
protected Calendar calendar;
protected NumberFormat numberFormat;
public final static int DEFAULT = 2;
public final static int FULL = 0;
public final static int LONG = 1;
public final static int MEDIUM = 2;
public final static int SHORT = 3;
public final static int ERA_FIELD = 0;
public final static int YEAR_FIELD = 1;
public final static int MONTH_FIELD = 2;
public final static int DATE_FIELD = 3;
public final static int HOUR_OF_DAY1_FIELD = 4;
public final static int HOUR_OF_DAY0_FIELD = 5;
public final static int MINUTE_FIELD = 6;
public final static int SECOND_FIELD = 7;
public final static int MILLISECOND_FIELD = 8;
public final static int DAY_OF_WEEK_FIELD = 9;
public final static int DAY_OF_YEAR_FIELD = 10;
public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
public final static int WEEK_OF_YEAR_FIELD = 12;
public final static int WEEK_OF_MONTH_FIELD = 13;
public final static int AM_PM_FIELD = 14;
public final static int HOUR1_FIELD = 15;
public final static int HOUR0_FIELD = 16;
public final static int TIMEZONE_FIELD = 17;
protected DateFormat() {
}
@Override
public Object clone() {
DateFormat clone = (DateFormat) super.clone();
clone.calendar = (Calendar) calendar.clone();
clone.numberFormat = (NumberFormat) numberFormat.clone();
return clone;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof DateFormat)) {
return false;
}
DateFormat dateFormat = (DateFormat) object;
return numberFormat.equals(dateFormat.numberFormat) &&
calendar.getTimeZone().equals(dateFormat.calendar.getTimeZone()) &&
calendar.getFirstDayOfWeek() == dateFormat.calendar.getFirstDayOfWeek() &&
calendar.getMinimalDaysInFirstWeek() == dateFormat.calendar.getMinimalDaysInFirstWeek() &&
calendar.isLenient() == dateFormat.calendar.isLenient();
}
@Override
public final StringBuffer format(Object object, StringBuffer buffer, FieldPosition field) {
if (object instanceof Date) {
return format((Date) object, buffer, field);
}
if (object instanceof Number) {
return format(new Date(((Number) object).longValue()), buffer, field);
}
throw new IllegalArgumentException();
}
public final String format(Date date) {
return format(date, new StringBuffer(), new FieldPosition(0)).toString();
}
public abstract StringBuffer format(Date date, StringBuffer buffer, FieldPosition field);
public static TLocale[] getAvailableLocales() {
return TLocale.getAvailableLocales();
}
public Calendar getCalendar() {
return calendar;
}
public final static DateFormat getDateInstance() {
return getDateInstance(DEFAULT);
}
public final static DateFormat getDateInstance(int style) {
checkDateStyle(style);
return getDateInstance(style, TLocale.getDefault());
}
public final static DateFormat getDateInstance(int style, TLocale locale) {
checkDateStyle(style);
com.ibm.icu.text.DateFormat icuFormat = com.ibm.icu.text.DateFormat.getDateInstance(style, locale);
return new SimpleDateFormat(locale, (com.ibm.icu.text.SimpleDateFormat) icuFormat);
}
public final static DateFormat getDateTimeInstance() {
return getDateTimeInstance(DEFAULT, DEFAULT);
}
public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle) {
checkTimeStyle(timeStyle);
checkDateStyle(dateStyle);
return getDateTimeInstance(dateStyle, timeStyle, TLocale.getDefault());
}
public final static DateFormat getDateTimeInstance(int dateStyle, int timeStyle, TLocale locale) {
checkTimeStyle(timeStyle);
checkDateStyle(dateStyle);
com.ibm.icu.text.DateFormat icuFormat = com.ibm.icu.text.DateFormat.getDateTimeInstance(dateStyle, timeStyle,
locale);
return new SimpleDateFormat(locale, (com.ibm.icu.text.SimpleDateFormat) icuFormat);
}
public final static DateFormat getInstance() {
return getDateTimeInstance(SHORT, SHORT);
}
public NumberFormat getNumberFormat() {
return numberFormat;
}
static String getStyleName(int style) {
String styleName;
switch (style) {
case SHORT:
styleName = "SHORT";
break;
case MEDIUM:
styleName = "MEDIUM";
break;
case LONG:
styleName = "LONG";
break;
case FULL:
styleName = "FULL";
break;
default:
styleName = "";
}
return styleName;
}
public final static DateFormat getTimeInstance() {
return getTimeInstance(DEFAULT);
}
public final static DateFormat getTimeInstance(int style) {
checkTimeStyle(style);
return getTimeInstance(style, TLocale.getDefault());
}
public final static DateFormat getTimeInstance(int style, TLocale locale) {
checkTimeStyle(style);
com.ibm.icu.text.DateFormat icuFormat = com.ibm.icu.text.DateFormat.getTimeInstance(style, locale);
return new SimpleDateFormat(locale, (com.ibm.icu.text.SimpleDateFormat) icuFormat);
}
public TimeZone getTimeZone() {
return calendar.getTimeZone();
}
@Override
public int hashCode() {
return calendar.getFirstDayOfWeek() + calendar.getMinimalDaysInFirstWeek() + calendar.getTimeZone().hashCode() +
(calendar.isLenient() ? 1231 : 1237) + numberFormat.hashCode();
}
public boolean isLenient() {
return calendar.isLenient();
}
public Date parse(String string) throws ParseException {
ParsePosition position = new ParsePosition(0);
Date date = parse(string, position);
if (position.getIndex() == 0) {
throw new ParseException("Unparseable date" + string, position.getErrorIndex());
}
return date;
}
public abstract Date parse(String string, ParsePosition position);
@Override
public Object parseObject(String string, ParsePosition position) {
return parse(string, position);
}
public void setCalendar(Calendar cal) {
calendar = cal;
}
public void setLenient(boolean value) {
calendar.setLenient(value);
}
public void setNumberFormat(NumberFormat format) {
numberFormat = format;
}
public void setTimeZone(TimeZone timezone) {
calendar.setTimeZone(timezone);
}
public static class Field extends Format.Field {
private static THashMap<Integer, Field> table = new THashMap<>();
public final static Field ERA = new Field("era", Calendar.ERA);
public final static Field YEAR = new Field("year", Calendar.YEAR);
public final static Field MONTH = new Field("month", Calendar.MONTH);
public final static Field HOUR_OF_DAY0 = new Field("hour of day", Calendar.HOUR_OF_DAY);
public final static Field HOUR_OF_DAY1 = new Field("hour of day 1", -1);
public final static Field MINUTE = new Field("minute", Calendar.MINUTE);
public final static Field SECOND = new Field("second", Calendar.SECOND);
public final static Field MILLISECOND = new Field("millisecond", Calendar.MILLISECOND);
public final static Field DAY_OF_WEEK = new Field("day of week", Calendar.DAY_OF_WEEK);
public final static Field DAY_OF_MONTH = new Field("day of month", Calendar.DAY_OF_MONTH);
public final static Field DAY_OF_YEAR = new Field("day of year", Calendar.DAY_OF_YEAR);
public final static Field DAY_OF_WEEK_IN_MONTH = new Field("day of week in month",
Calendar.DAY_OF_WEEK_IN_MONTH);
public final static Field WEEK_OF_YEAR = new Field("week of year", Calendar.WEEK_OF_YEAR);
public final static Field WEEK_OF_MONTH = new Field("week of month", Calendar.WEEK_OF_MONTH);
public final static Field AM_PM = new Field("am pm", Calendar.AM_PM);
public final static Field HOUR0 = new Field("hour", Calendar.HOUR);
public final static Field HOUR1 = new Field("hour 1", -1);
public final static Field TIME_ZONE = new Field("time zone", -1);
private int calendarField = -1;
protected Field(String fieldName, int calendarField) {
super(fieldName);
this.calendarField = calendarField;
if (calendarField != -1 && table.get(new Integer(calendarField)) == null) {
table.put(new Integer(calendarField), this);
}
}
public int getCalendarField() {
return calendarField;
}
public static Field ofCalendarField(int calendarField) {
if (calendarField < 0 || calendarField >= Calendar.FIELD_COUNT) {
throw new IllegalArgumentException();
}
return table.get(new Integer(calendarField));
}
}
private static void checkDateStyle(int style) {
if (!(style == SHORT || style == MEDIUM || style == LONG || style == FULL || style == DEFAULT)) {
throw new IllegalArgumentException("Illegal date style: " + style);
}
}
private static void checkTimeStyle(int style) {
if (!(style == SHORT || style == MEDIUM || style == LONG || style == FULL || style == DEFAULT)) {
// text.0F=Illegal time style: {0}
throw new IllegalArgumentException("Illegal time style: " + style);
}
}
}

View File

@ -0,0 +1,240 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import java.util.Arrays;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.util.TLocale;
public class DateFormatSymbols implements TSerializable, Cloneable {
private static final long serialVersionUID = -5987973545549424702L;
private String localPatternChars;
String[] ampms, eras, months, shortMonths, shortWeekdays, weekdays;
String[][] zoneStrings;
transient private com.ibm.icu.text.DateFormatSymbols icuSymbols;
public DateFormatSymbols() {
this(TLocale.getDefault());
}
public DateFormatSymbols(TLocale locale) {
this(locale, new com.ibm.icu.text.DateFormatSymbols(locale));
}
DateFormatSymbols(TLocale locale, com.ibm.icu.text.DateFormatSymbols icuSymbols) {
this.icuSymbols = icuSymbols;
localPatternChars = icuSymbols.getLocalPatternChars();
ampms = icuSymbols.getAmPmStrings();
eras = icuSymbols.getEras();
months = icuSymbols.getMonths();
shortMonths = icuSymbols.getShortMonths();
shortWeekdays = icuSymbols.getShortWeekdays();
weekdays = icuSymbols.getWeekdays();
}
@Override
public Object clone() {
if (zoneStrings == null) {
zoneStrings = icuSymbols.getZoneStrings();
}
try {
DateFormatSymbols symbols = (DateFormatSymbols) super.clone();
symbols.ampms = ampms.clone();
symbols.eras = eras.clone();
symbols.months = months.clone();
symbols.shortMonths = shortMonths.clone();
symbols.shortWeekdays = shortWeekdays.clone();
symbols.weekdays = weekdays.clone();
symbols.zoneStrings = new String[zoneStrings.length][];
for (int i = 0; i < zoneStrings.length; i++) {
symbols.zoneStrings[i] = zoneStrings[i].clone();
}
return symbols;
} catch (CloneNotSupportedException e) {
return null;
}
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof DateFormatSymbols)) {
return false;
}
if (zoneStrings == null) {
zoneStrings = icuSymbols.getZoneStrings();
}
DateFormatSymbols obj = (DateFormatSymbols) object;
if (obj.zoneStrings == null) {
obj.zoneStrings = obj.icuSymbols.getZoneStrings();
}
if (!localPatternChars.equals(obj.localPatternChars)) {
return false;
}
if (!Arrays.equals(ampms, obj.ampms)) {
return false;
}
if (!Arrays.equals(eras, obj.eras)) {
return false;
}
if (!Arrays.equals(months, obj.months)) {
return false;
}
if (!Arrays.equals(shortMonths, obj.shortMonths)) {
return false;
}
if (!Arrays.equals(shortWeekdays, obj.shortWeekdays)) {
return false;
}
if (!Arrays.equals(weekdays, obj.weekdays)) {
return false;
}
if (zoneStrings.length != obj.zoneStrings.length) {
return false;
}
for (String[] element : zoneStrings) {
if (element.length != element.length) {
return false;
}
for (int j = 0; j < element.length; j++) {
if (element[j] != element[j] && !(element[j].equals(element[j]))) {
return false;
}
}
}
return true;
}
public String[] getAmPmStrings() {
return ampms.clone();
}
public String[] getEras() {
return eras.clone();
}
public String getLocalPatternChars() {
return localPatternChars;
}
public String[] getMonths() {
return months.clone();
}
public String[] getShortMonths() {
return shortMonths.clone();
}
public String[] getShortWeekdays() {
return shortWeekdays.clone();
}
public String[] getWeekdays() {
return weekdays.clone();
}
public String[][] getZoneStrings() {
if (zoneStrings == null) {
zoneStrings = icuSymbols.getZoneStrings();
}
String[][] clone = new String[zoneStrings.length][];
for (int i = zoneStrings.length; --i >= 0;) {
clone[i] = zoneStrings[i].clone();
}
return clone;
}
@Override
public int hashCode() {
if (zoneStrings == null) {
zoneStrings = icuSymbols.getZoneStrings();
}
int hashCode;
hashCode = localPatternChars.hashCode();
for (String element : ampms) {
hashCode += element.hashCode();
}
for (String element : eras) {
hashCode += element.hashCode();
}
for (String element : months) {
hashCode += element.hashCode();
}
for (String element : shortMonths) {
hashCode += element.hashCode();
}
for (String element : shortWeekdays) {
hashCode += element.hashCode();
}
for (String element : weekdays) {
hashCode += element.hashCode();
}
for (String[] element : zoneStrings) {
for (int j = 0; j < element.length; j++) {
if (element[j] != null) {
hashCode += element[j].hashCode();
}
}
}
return hashCode;
}
public void setAmPmStrings(String[] data) {
ampms = data.clone();
}
public void setEras(String[] data) {
eras = data.clone();
}
public void setLocalPatternChars(String data) {
if (data == null) {
throw new NullPointerException();
}
localPatternChars = data;
}
public void setMonths(String[] data) {
months = data.clone();
}
public void setShortMonths(String[] data) {
shortMonths = data.clone();
}
public void setShortWeekdays(String[] data) {
shortWeekdays = data.clone();
}
public void setWeekdays(String[] data) {
weekdays = data.clone();
}
public void setZoneStrings(String[][] data) {
zoneStrings = data.clone();
}
}

View File

@ -0,0 +1,432 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.util.TLocale;
public class DecimalFormat extends NumberFormat {
private static final long serialVersionUID = 864413376551465018L;
private transient boolean parseBigDecimal = false;
private transient DecimalFormatSymbols symbols;
private transient com.ibm.icu.text.DecimalFormat dform;
private transient com.ibm.icu.text.DecimalFormatSymbols icuSymbols;
private static final int CURRENT_SERIAL_VERTION = 3;
private transient int serialVersionOnStream = 3;
/**
* Constructs a new {@code DecimalFormat} for formatting and parsing numbers
* for the default locale.
*/
public DecimalFormat() {
TLocale locale = TLocale.getDefault();
icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale);
symbols = new DecimalFormatSymbols(locale);
dform = new com.ibm.icu.text.DecimalFormat();
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
* Constructs a new {@code DecimalFormat} using the specified non-localized
* pattern and the {@code DecimalFormatSymbols} for the default Locale.
*
* @param pattern
* the non-localized pattern.
* @throws IllegalArgumentException
* if the pattern cannot be parsed.
*/
public DecimalFormat(String pattern) {
TLocale locale = TLocale.getDefault();
icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale);
symbols = new DecimalFormatSymbols(locale);
dform = new com.ibm.icu.text.DecimalFormat(pattern, icuSymbols);
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
* Constructs a new {@code DecimalFormat} using the specified non-localized
* pattern and {@code DecimalFormatSymbols}.
*
* @param pattern
* the non-localized pattern.
* @param value
* the DecimalFormatSymbols.
* @throws IllegalArgumentException
* if the pattern cannot be parsed.
*/
public DecimalFormat(String pattern, DecimalFormatSymbols value) {
symbols = (DecimalFormatSymbols) value.clone();
TLocale locale = symbols.getLocale();
icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale);
copySymbols(icuSymbols, symbols);
dform = new com.ibm.icu.text.DecimalFormat(pattern, icuSymbols);
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
DecimalFormat(String pattern, DecimalFormatSymbols value, com.ibm.icu.text.DecimalFormat icuFormat) {
symbols = value;
icuSymbols = value.getIcuSymbols();
dform = icuFormat;
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
* Changes the pattern of this decimal format to the specified pattern which
* uses localized pattern characters.
*
* @param pattern
* the localized pattern.
* @throws IllegalArgumentException
* if the pattern cannot be parsed.
*/
public void applyLocalizedPattern(String pattern) {
dform.applyLocalizedPattern(pattern);
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
* Changes the pattern of this decimal format to the specified pattern which
* uses non-localized pattern characters.
*
* @param pattern
* the non-localized pattern.
* @throws IllegalArgumentException
* if the pattern cannot be parsed.
*/
public void applyPattern(String pattern) {
dform.applyPattern(pattern);
super.setMaximumFractionDigits(dform.getMaximumFractionDigits());
super.setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
super.setMinimumFractionDigits(dform.getMinimumFractionDigits());
super.setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
}
/**
* Returns a new instance of {@code DecimalFormat} with the same pattern and
* properties as this decimal format.
*
* @return a shallow copy of this decimal format.
* @see java.lang.Cloneable
*/
@Override
public Object clone() {
DecimalFormat clone = (DecimalFormat) super.clone();
clone.dform = (com.ibm.icu.text.DecimalFormat) dform.clone();
clone.symbols = (DecimalFormatSymbols) symbols.clone();
return clone;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof DecimalFormat)) {
return false;
}
DecimalFormat format = (DecimalFormat) object;
return (this.dform == null ? format.dform == null : this.dform
.equals(format.dform));
}
@Override
public AttributedCharacterIterator formatToCharacterIterator(Object object) {
if (object == null) {
throw new NullPointerException();
}
return dform.formatToCharacterIterator(object);
}
@Override
public StringBuffer format(double value, StringBuffer buffer,
FieldPosition position) {
return dform.format(value, buffer, position);
}
@Override
public StringBuffer format(long value, StringBuffer buffer,
FieldPosition position) {
return dform.format(value, buffer, position);
}
@Override
public final StringBuffer format(Object number, StringBuffer toAppendTo,
FieldPosition pos) {
if (!(number instanceof Number)) {
throw new IllegalArgumentException();
}
if (toAppendTo == null || pos == null) {
throw new NullPointerException();
}
if (number instanceof BigInteger || number instanceof BigDecimal) {
return dform.format(number, toAppendTo, pos);
}
return super.format(number, toAppendTo, pos);
}
public DecimalFormatSymbols getDecimalFormatSymbols() {
return (DecimalFormatSymbols) symbols.clone();
}
@Override
public Currency getCurrency() {
final com.ibm.icu.util.Currency cur = dform.getCurrency();
final String code = (cur == null) ? "XXX" : cur.getCurrencyCode(); //$NON-NLS-1$
return Currency.getInstance(code);
}
public int getGroupingSize() {
return dform.getGroupingSize();
}
public int getMultiplier() {
return dform.getMultiplier();
}
public String getNegativePrefix() {
return dform.getNegativePrefix();
}
public String getNegativeSuffix() {
return dform.getNegativeSuffix();
}
public String getPositivePrefix() {
return dform.getPositivePrefix();
}
public String getPositiveSuffix() {
return dform.getPositiveSuffix();
}
@Override
public int hashCode() {
return dform.hashCode();
}
public boolean isDecimalSeparatorAlwaysShown() {
return dform.isDecimalSeparatorAlwaysShown();
}
public boolean isParseBigDecimal() {
return this.parseBigDecimal;
}
@Override
public void setParseIntegerOnly(boolean value) {
// In this implementation, com.ibm.icu.text.DecimalFormat is wrapped to
// fulfill most of the format and parse feature. And this method is
// delegated to the wrapped instance of com.ibm.icu.text.DecimalFormat.
dform.setParseIntegerOnly(value);
}
@Override
public boolean isParseIntegerOnly() {
return dform.isParseIntegerOnly();
}
private static final Double NEGATIVE_ZERO_DOUBLE = new Double(-0.0);
@Override
public Number parse(String string, ParsePosition position) {
Number number = dform.parse(string, position);
if (null == number) {
return null;
}
if (this.isParseBigDecimal()) {
if (number instanceof Long) {
return new BigDecimal(number.longValue());
}
if ((number instanceof Double) && !((Double) number).isInfinite()
&& !((Double) number).isNaN()) {
return new BigDecimal(number.doubleValue());
}
if (number instanceof BigInteger) {
return new BigDecimal(number.doubleValue());
}
if (number instanceof com.ibm.icu.math.BigDecimal) {
return new BigDecimal(number.toString());
}
return number;
}
if ((number instanceof com.ibm.icu.math.BigDecimal)
|| (number instanceof BigInteger)) {
return new Double(number.doubleValue());
}
if (this.isParseIntegerOnly() && number.equals(NEGATIVE_ZERO_DOUBLE)) {
return new Long(0);
}
return number;
}
public void setDecimalFormatSymbols(DecimalFormatSymbols value) {
if (value != null) {
symbols = (DecimalFormatSymbols) value.clone();
icuSymbols = dform.getDecimalFormatSymbols();
copySymbols(icuSymbols, symbols);
dform.setDecimalFormatSymbols(icuSymbols);
}
}
@Override
public void setCurrency(Currency currency) {
dform.setCurrency(com.ibm.icu.util.Currency.getInstance(currency
.getCurrencyCode()));
symbols.setCurrency(currency);
}
public void setDecimalSeparatorAlwaysShown(boolean value) {
dform.setDecimalSeparatorAlwaysShown(value);
}
public void setGroupingSize(int value) {
dform.setGroupingSize(value);
}
@Override
public void setGroupingUsed(boolean value) {
dform.setGroupingUsed(value);
}
@Override
public boolean isGroupingUsed() {
return dform.isGroupingUsed();
}
@Override
public void setMaximumFractionDigits(int value) {
super.setMaximumFractionDigits(value);
dform.setMaximumFractionDigits(value);
}
@Override
public void setMaximumIntegerDigits(int value) {
super.setMaximumIntegerDigits(value);
dform.setMaximumIntegerDigits(value);
}
@Override
public void setMinimumFractionDigits(int value) {
super.setMinimumFractionDigits(value);
dform.setMinimumFractionDigits(value);
}
@Override
public void setMinimumIntegerDigits(int value) {
super.setMinimumIntegerDigits(value);
dform.setMinimumIntegerDigits(value);
}
public void setMultiplier(int value) {
dform.setMultiplier(value);
}
public void setNegativePrefix(String value) {
dform.setNegativePrefix(value);
}
public void setNegativeSuffix(String value) {
dform.setNegativeSuffix(value);
}
public void setPositivePrefix(String value) {
dform.setPositivePrefix(value);
}
public void setPositiveSuffix(String value) {
dform.setPositiveSuffix(value);
}
public void setParseBigDecimal(boolean newValue) {
this.parseBigDecimal = newValue;
}
public String toLocalizedPattern() {
return dform.toLocalizedPattern();
}
public String toPattern() {
return dform.toPattern();
}
/*
* Copies decimal format symbols from text object to ICU one.
*
* @param icu the object which receives the new values. @param dfs the
* object which contains the new values.
*/
private void copySymbols(final com.ibm.icu.text.DecimalFormatSymbols icu,
final DecimalFormatSymbols dfs) {
Currency currency = dfs.getCurrency();
if (currency == null) {
icu.setCurrency(com.ibm.icu.util.Currency.getInstance("XXX")); //$NON-NLS-1$
} else {
icu.setCurrency(com.ibm.icu.util.Currency.getInstance(dfs
.getCurrency().getCurrencyCode()));
}
icu.setCurrencySymbol(dfs.getCurrencySymbol());
icu.setDecimalSeparator(dfs.getDecimalSeparator());
icu.setDigit(dfs.getDigit());
icu.setGroupingSeparator(dfs.getGroupingSeparator());
icu.setInfinity(dfs.getInfinity());
icu
.setInternationalCurrencySymbol(dfs
.getInternationalCurrencySymbol());
icu.setMinusSign(dfs.getMinusSign());
icu.setMonetaryDecimalSeparator(dfs.getMonetaryDecimalSeparator());
icu.setNaN(dfs.getNaN());
icu.setPatternSeparator(dfs.getPatternSeparator());
icu.setPercent(dfs.getPercent());
icu.setPerMill(dfs.getPerMill());
icu.setZeroDigit(dfs.getZeroDigit());
}
}

View File

@ -0,0 +1,280 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import java.util.Arrays;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneable;
import org.teavm.classlib.java.util.TLocale;
public final class DecimalFormatSymbols implements TCloneable, TSerializable {
private final int ZeroDigit = 0, Digit = 1, DecimalSeparator = 2,
GroupingSeparator = 3, PatternSeparator = 4, Percent = 5,
PerMill = 6, Exponent = 7, MonetaryDecimalSeparator = 8,
MinusSign = 9;
transient char[] patternChars;
private transient Currency currency;
private transient TLocale locale;
private String infinity, NaN, currencySymbol, intlCurrencySymbol;
/**
* Constructs a new {@code DecimalFormatSymbols} containing the symbols for
* the default locale. Best practice is to create a {@code DecimalFormat}
* and then to get the {@code DecimalFormatSymbols} from that object by
* calling {@link DecimalFormat#getDecimalFormatSymbols()}.
*/
public DecimalFormatSymbols() {
this(TLocale.getDefault());
}
/**
* Constructs a new DecimalFormatSymbols containing the symbols for the
* specified Locale. Best practice is to create a {@code DecimalFormat}
* and then to get the {@code DecimalFormatSymbols} from that object by
* calling {@link DecimalFormat#getDecimalFormatSymbols()}.
*
* @param locale
* the locale.
*/
public DecimalFormatSymbols(TLocale locale) {
this(locale, new com.ibm.icu.text.DecimalFormatSymbols(locale));
}
transient private com.ibm.icu.text.DecimalFormatSymbols icuSymbols;
DecimalFormatSymbols(TLocale locale, com.ibm.icu.text.DecimalFormatSymbols icuSymbols) {
this.icuSymbols = icuSymbols;
infinity = icuSymbols.getInfinity();
NaN = icuSymbols.getNaN();
this.locale = locale;
currencySymbol = icuSymbols.getCurrencySymbol();
intlCurrencySymbol = icuSymbols.getInternationalCurrencySymbol();
if (locale.getCountry().length() == 0) {
currency = Currency.getInstance("XXX"); //$NON-NLS-1$
} else {
currency = Currency.getInstance(locale);
}
patternChars = new char[10];
patternChars[ZeroDigit] = icuSymbols.getZeroDigit();
patternChars[Digit] = icuSymbols.getDigit();
patternChars[DecimalSeparator] = icuSymbols.getDecimalSeparator();
patternChars[GroupingSeparator] = icuSymbols.getGroupingSeparator();
patternChars[PatternSeparator] = icuSymbols.getPatternSeparator();
patternChars[Percent] = icuSymbols.getPercent();
patternChars[PerMill] = icuSymbols.getPerMill();
patternChars[Exponent] = icuSymbols.getExponentSeparator().charAt(0);
patternChars[MonetaryDecimalSeparator] = icuSymbols
.getMonetaryDecimalSeparator();
patternChars[MinusSign] = icuSymbols.getMinusSign();
}
@Override
public Object clone() {
try {
DecimalFormatSymbols symbols = (DecimalFormatSymbols) super.clone();
symbols.patternChars = patternChars.clone();
return symbols;
} catch (CloneNotSupportedException e) {
return null;
}
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof DecimalFormatSymbols)) {
return false;
}
DecimalFormatSymbols obj = (DecimalFormatSymbols) object;
return Arrays.equals(patternChars, obj.patternChars)
&& infinity.equals(obj.infinity) && NaN.equals(obj.NaN)
&& currencySymbol.equals(obj.currencySymbol)
&& intlCurrencySymbol.equals(obj.intlCurrencySymbol);
}
public Currency getCurrency() {
return currency;
}
public String getInternationalCurrencySymbol() {
return intlCurrencySymbol;
}
public String getCurrencySymbol() {
return currencySymbol;
}
public char getDecimalSeparator() {
return patternChars[DecimalSeparator];
}
public char getDigit() {
return patternChars[Digit];
}
public char getGroupingSeparator() {
return patternChars[GroupingSeparator];
}
public String getInfinity() {
return infinity;
}
String getLocalPatternChars() {
// Don't include the MonetaryDecimalSeparator or the MinusSign
return new String(patternChars, 0, patternChars.length - 2);
}
public char getMinusSign() {
return patternChars[MinusSign];
}
public char getMonetaryDecimalSeparator() {
return patternChars[MonetaryDecimalSeparator];
}
public String getNaN() {
return NaN;
}
public char getPatternSeparator() {
return patternChars[PatternSeparator];
}
public char getPercent() {
return patternChars[Percent];
}
public char getPerMill() {
return patternChars[PerMill];
}
public char getZeroDigit() {
return patternChars[ZeroDigit];
}
char getExponential() {
return patternChars[Exponent];
}
@Override
public int hashCode() {
return new String(patternChars).hashCode() + infinity.hashCode()
+ NaN.hashCode() + currencySymbol.hashCode()
+ intlCurrencySymbol.hashCode();
}
public void setCurrency(Currency currency) {
if (currency == null) {
throw new NullPointerException();
}
if (currency == this.currency) {
return;
}
this.currency = currency;
intlCurrencySymbol = currency.getCurrencyCode();
currencySymbol = currency.getSymbol(locale);
}
public void setInternationalCurrencySymbol(String value) {
if (value == null) {
currency = null;
intlCurrencySymbol = null;
return;
}
if (value.equals(intlCurrencySymbol)) {
return;
}
try {
currency = Currency.getInstance(value);
currencySymbol = currency.getSymbol(locale);
} catch (IllegalArgumentException e) {
currency = null;
}
intlCurrencySymbol = value;
}
public void setCurrencySymbol(String value) {
currencySymbol = value;
}
public void setDecimalSeparator(char value) {
patternChars[DecimalSeparator] = value;
}
public void setDigit(char value) {
patternChars[Digit] = value;
}
public void setGroupingSeparator(char value) {
patternChars[GroupingSeparator] = value;
}
public void setInfinity(String value) {
infinity = value;
}
public void setMinusSign(char value) {
patternChars[MinusSign] = value;
}
public void setMonetaryDecimalSeparator(char value) {
patternChars[MonetaryDecimalSeparator] = value;
}
public void setNaN(String value) {
NaN = value;
}
public void setPatternSeparator(char value) {
patternChars[PatternSeparator] = value;
}
public void setPercent(char value) {
patternChars[Percent] = value;
}
public void setPerMill(char value) {
patternChars[PerMill] = value;
}
public void setZeroDigit(char value) {
patternChars[ZeroDigit] = value;
}
void setExponential(char value) {
patternChars[Exponent] = value;
}
TLocale getLocale(){
return locale;
}
com.ibm.icu.text.DecimalFormatSymbols getIcuSymbols() {
return icuSymbols;
}
}

View File

@ -0,0 +1,87 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
public class FieldPosition {
private int myField, beginIndex, endIndex;
private Format.Field myAttribute;
public FieldPosition(int field) {
myField = field;
}
public FieldPosition(Format.Field attribute) {
myAttribute = attribute;
myField = -1;
}
public FieldPosition(Format.Field attribute, int field) {
myAttribute = attribute;
myField = field;
}
void clear() {
beginIndex = endIndex = 0;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof FieldPosition)) {
return false;
}
FieldPosition pos = (FieldPosition) object;
return myField == pos.myField && myAttribute == pos.myAttribute && beginIndex == pos.beginIndex &&
endIndex == pos.endIndex;
}
public int getBeginIndex() {
return beginIndex;
}
public int getEndIndex() {
return endIndex;
}
public int getField() {
return myField;
}
public Format.Field getFieldAttribute() {
return myAttribute;
}
@Override
public int hashCode() {
int attributeHash = (myAttribute == null) ? 0 : myAttribute.hashCode();
return attributeHash + myField * 10 + beginIndex * 100 + endIndex;
}
public void setBeginIndex(int index) {
beginIndex = index;
}
public void setEndIndex(int index) {
endIndex = index;
}
@Override
public String toString() {
return getClass().getName() + "[attribute=" + myAttribute + ", field=" + myField + ", beginIndex=" +
beginIndex + ", endIndex=" + endIndex + "]";
}
}

View File

@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneable;
public abstract class Format implements TSerializable, TCloneable {
public Format() {
}
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
return null;
}
}
String convertPattern(String template, String fromChars, String toChars, boolean check) {
if (!check && fromChars.equals(toChars)) {
return template;
}
boolean quote = false;
StringBuilder output = new StringBuilder();
int length = template.length();
for (int i = 0; i < length; i++) {
int index;
char next = template.charAt(i);
if (next == '\'') {
quote = !quote;
}
if (!quote && (index = fromChars.indexOf(next)) != -1) {
output.append(toChars.charAt(index));
} else if (check && !quote && ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
throw new IllegalArgumentException("Invalid pattern char" + next + " in " + template);
} else {
output.append(next);
}
}
if (quote) {
throw new IllegalArgumentException("Unterminated quote");
}
return output.toString();
}
public final String format(Object object) {
return format(object, new StringBuffer(), new FieldPosition(0)).toString();
}
public abstract StringBuffer format(Object object, StringBuffer buffer, FieldPosition field);
public AttributedCharacterIterator formatToCharacterIterator(Object object) {
return new AttributedString(format(object)).getIterator();
}
public Object parseObject(String string) throws ParseException {
ParsePosition position = new ParsePosition(0);
Object result = parseObject(string, position);
if (position.getIndex() == 0) {
throw new ParseException("Format.parseObject(String) parse failure", position.getErrorIndex());
}
return result;
}
public abstract Object parseObject(String string, ParsePosition position);
static boolean upTo(String string, ParsePosition position, StringBuffer buffer, char stop) {
int index = position.getIndex(), length = string.length();
boolean lastQuote = false, quote = false;
while (index < length) {
char ch = string.charAt(index++);
if (ch == '\'') {
if (lastQuote) {
buffer.append('\'');
}
quote = !quote;
lastQuote = true;
} else if (ch == stop && !quote) {
position.setIndex(index);
return true;
} else {
lastQuote = false;
buffer.append(ch);
}
}
position.setIndex(index);
return false;
}
static boolean upToWithQuotes(String string, ParsePosition position, StringBuffer buffer, char stop, char start) {
int index = position.getIndex(), length = string.length(), count = 1;
boolean quote = false;
while (index < length) {
char ch = string.charAt(index++);
if (ch == '\'') {
quote = !quote;
}
if (!quote) {
if (ch == stop) {
count--;
}
if (count == 0) {
position.setIndex(index);
return true;
}
if (ch == start) {
count++;
}
}
buffer.append(ch);
}
throw new IllegalArgumentException("Unmatched braces in the pattern");
}
public static class Field extends AttributedCharacterIterator.Attribute {
protected Field(String fieldName) {
super(fieldName);
}
}
}

View File

@ -0,0 +1,263 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.util.TLocale;
public abstract class NumberFormat extends Format {
private static final long serialVersionUID = -2308460125733713944L;
public static final int INTEGER_FIELD = 0;
public static final int FRACTION_FIELD = 1;
private boolean groupingUsed = true, parseIntegerOnly = false;
private int maximumIntegerDigits = 40, minimumIntegerDigits = 1,
maximumFractionDigits = 3, minimumFractionDigits = 0;
public NumberFormat() {
}
@Override
public Object clone() {
return super.clone();
}
@Override
public boolean equals(Object object) {
if (object == this) {
return true;
}
if (!(object instanceof NumberFormat)) {
return false;
}
NumberFormat obj = (NumberFormat) object;
return groupingUsed == obj.groupingUsed
&& parseIntegerOnly == obj.parseIntegerOnly
&& maximumFractionDigits == obj.maximumFractionDigits
&& maximumIntegerDigits == obj.maximumIntegerDigits
&& minimumFractionDigits == obj.minimumFractionDigits
&& minimumIntegerDigits == obj.minimumIntegerDigits;
}
public final String format(double value) {
return format(value, new StringBuffer(), new FieldPosition(0))
.toString();
}
public abstract StringBuffer format(double value, StringBuffer buffer,
FieldPosition field);
public final String format(long value) {
return format(value, new StringBuffer(), new FieldPosition(0))
.toString();
}
public abstract StringBuffer format(long value, StringBuffer buffer,
FieldPosition field);
@Override
public StringBuffer format(Object object, StringBuffer buffer,
FieldPosition field) {
if (object instanceof Number) {
double dv = ((Number) object).doubleValue();
long lv = ((Number) object).longValue();
if (dv == lv) {
return format(lv, buffer, field);
}
return format(dv, buffer, field);
}
throw new IllegalArgumentException();
}
public static TLocale[] getAvailableLocales() {
return TLocale.getAvailableLocales();
}
public Currency getCurrency() {
throw new UnsupportedOperationException();
}
public final static NumberFormat getCurrencyInstance() {
return getCurrencyInstance(TLocale.getDefault());
}
public static NumberFormat getCurrencyInstance(TLocale locale) {
com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat
.getCurrencyInstance(locale);
String pattern = icuFormat.toPattern();
return new DecimalFormat(pattern, new DecimalFormatSymbols(locale));
}
public final static NumberFormat getIntegerInstance() {
return getIntegerInstance(TLocale.getDefault());
}
public static NumberFormat getIntegerInstance(TLocale locale) {
com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat
.getIntegerInstance(locale);
String pattern = icuFormat.toPattern();
DecimalFormat format = new DecimalFormat(pattern, new DecimalFormatSymbols(locale));
format.setParseIntegerOnly(true);
return format;
}
public final static NumberFormat getInstance() {
return getNumberInstance();
}
public static NumberFormat getInstance(TLocale locale) {
return getNumberInstance(locale);
}
public int getMaximumFractionDigits() {
return maximumFractionDigits;
}
public int getMaximumIntegerDigits() {
return maximumIntegerDigits;
}
public int getMinimumFractionDigits() {
return minimumFractionDigits;
}
public int getMinimumIntegerDigits() {
return minimumIntegerDigits;
}
public final static NumberFormat getNumberInstance() {
return getNumberInstance(TLocale.getDefault());
}
public static NumberFormat getNumberInstance(TLocale locale) {
com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat
.getNumberInstance(locale);
String pattern = icuFormat.toPattern();
return new DecimalFormat(pattern, new DecimalFormatSymbols(locale, icuFormat.getDecimalFormatSymbols()), icuFormat);
}
public final static NumberFormat getPercentInstance() {
return getPercentInstance(TLocale.getDefault());
}
public static NumberFormat getPercentInstance(TLocale locale) {
com.ibm.icu.text.DecimalFormat icuFormat = (com.ibm.icu.text.DecimalFormat) com.ibm.icu.text.NumberFormat
.getPercentInstance(locale);
String pattern = icuFormat.toPattern();
return new DecimalFormat(pattern, new DecimalFormatSymbols(locale));
}
@Override
public int hashCode() {
return (groupingUsed ? 1231 : 1237) + (parseIntegerOnly ? 1231 : 1237)
+ maximumFractionDigits + maximumIntegerDigits
+ minimumFractionDigits + minimumIntegerDigits;
}
public boolean isGroupingUsed() {
return groupingUsed;
}
public boolean isParseIntegerOnly() {
return parseIntegerOnly;
}
public Number parse(String string) throws ParseException {
ParsePosition pos = new ParsePosition(0);
Number number = parse(string, pos);
if (pos.getIndex() == 0) {
throw new ParseException("Unparseable number: " + string, pos.getErrorIndex());
}
return number;
}
public abstract Number parse(String string, ParsePosition position);
@Override
public final Object parseObject(String string, ParsePosition position) {
if (position == null) {
throw new NullPointerException("position is null");
}
try {
return parse(string, position);
} catch (Exception e) {
return null;
}
}
public void setCurrency(Currency currency) {
throw new UnsupportedOperationException();
}
public void setGroupingUsed(boolean value) {
groupingUsed = value;
}
public void setMaximumFractionDigits(int value) {
maximumFractionDigits = value < 0 ? 0 : value;
if (maximumFractionDigits < minimumFractionDigits) {
minimumFractionDigits = maximumFractionDigits;
}
}
public void setMaximumIntegerDigits(int value) {
maximumIntegerDigits = value < 0 ? 0 : value;
if (maximumIntegerDigits < minimumIntegerDigits) {
minimumIntegerDigits = maximumIntegerDigits;
}
}
public void setMinimumFractionDigits(int value) {
minimumFractionDigits = value < 0 ? 0 : value;
if (maximumFractionDigits < minimumFractionDigits) {
maximumFractionDigits = minimumFractionDigits;
}
}
public void setMinimumIntegerDigits(int value) {
minimumIntegerDigits = value < 0 ? 0 : value;
if (maximumIntegerDigits < minimumIntegerDigits) {
maximumIntegerDigits = minimumIntegerDigits;
}
}
public void setParseIntegerOnly(boolean value) {
parseIntegerOnly = value;
}
public static class Field extends Format.Field {
public static final Field SIGN = new Field("sign");
public static final Field INTEGER = new Field("integer");
public static final Field FRACTION = new Field("fraction");
public static final Field EXPONENT = new Field("exponent");
public static final Field EXPONENT_SIGN = new Field("exponent sign");
public static final Field EXPONENT_SYMBOL = new Field("exponent symbol");
public static final Field DECIMAL_SEPARATOR = new Field("decimal separator");
public static final Field GROUPING_SEPARATOR = new Field("grouping separator");
public static final Field PERCENT = new Field("percent");
public static final Field PERMILLE = new Field("per mille");
public static final Field CURRENCY = new Field("currency");
protected Field(String fieldName) {
super(fieldName);
}
}
}

View File

@ -0,0 +1,51 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
/**
* Thrown when the string being parsed is not in the correct form.
*/
public class ParseException extends Exception {
private static final long serialVersionUID = 2703218443322787634L;
private int errorOffset;
/**
* Constructs a new instance of this class with its stack trace, detail
* message and the location of the error filled in.
*
* @param detailMessage
* the detail message for this exception.
* @param location
* the index at which the parse exception occurred.
*/
public ParseException(String detailMessage, int location) {
super(detailMessage);
errorOffset = location;
}
/**
* Returns the index at which this parse exception occurred.
*
* @return the location of this exception in the parsed string.
*/
public int getErrorOffset() {
return errorOffset;
}
}

View File

@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
public class ParsePosition {
private int currentPosition, errorIndex = -1;
public ParsePosition(int index) {
currentPosition = index;
}
@Override
public boolean equals(Object object) {
if (!(object instanceof ParsePosition)) {
return false;
}
ParsePosition pos = (ParsePosition) object;
return currentPosition == pos.currentPosition && errorIndex == pos.errorIndex;
}
public int getErrorIndex() {
return errorIndex;
}
public int getIndex() {
return currentPosition;
}
@Override
public int hashCode() {
return currentPosition + errorIndex;
}
public void setErrorIndex(int index) {
errorIndex = index;
}
public void setIndex(int index) {
currentPosition = index;
}
@Override
public String toString() {
return getClass().getName() + "[index=" + currentPosition + ", errorIndex=" + errorIndex + "]";
}
}

View File

@ -0,0 +1,597 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.teavm.classlib.java.text;
import org.teavm.classlib.java.util.*;
public class SimpleDateFormat extends DateFormat {
private static final long serialVersionUID = 4774881970558875024L;
private static final String patternChars = "GyMdkHmsSEDFwWahKzYeugAZvcLQqV"; //$NON-NLS-1$
private String pattern;
private DateFormatSymbols formatData;
transient private int creationYear;
private Date defaultCenturyStart;
private transient String tzId;
private transient com.ibm.icu.text.SimpleDateFormat icuFormat;
public SimpleDateFormat() {
this(TLocale.getDefault());
icuFormat = new com.ibm.icu.text.SimpleDateFormat();
icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
pattern = (String) getInternalField("pattern", icuFormat);
formatData = new DateFormatSymbols(TLocale.getDefault());
}
public SimpleDateFormat(String pattern) {
this(pattern, TLocale.getDefault());
}
private void validateFormat(char format) {
int index = patternChars.indexOf(format);
if (index == -1) {
throw new IllegalArgumentException("Unknown pattern character - " + format);
}
}
private void validatePattern(String template) {
boolean quote = false;
int next, last = -1, count = 0;
final int patternLength = template.length();
for (int i = 0; i < patternLength; i++) {
next = (template.charAt(i));
if (next == '\'') {
if (count > 0) {
validateFormat((char) last);
count = 0;
}
if (last == next) {
last = -1;
} else {
last = next;
}
quote = !quote;
continue;
}
if (!quote && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
if (last == next) {
count++;
} else {
if (count > 0) {
validateFormat((char) last);
}
last = next;
count = 1;
}
} else {
if (count > 0) {
validateFormat((char) last);
count = 0;
}
last = -1;
}
}
if (count > 0) {
validateFormat((char) last);
}
if (quote) {
throw new IllegalArgumentException("Unterminated quote");
}
}
public SimpleDateFormat(String template, DateFormatSymbols value) {
this(TLocale.getDefault());
validatePattern(template);
icuFormat = new com.ibm.icu.text.SimpleDateFormat(template, Locale.getDefault());
icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
pattern = template;
formatData = (DateFormatSymbols) value.clone();
}
private void copySymbols(DateFormatSymbols value, com.ibm.icu.text.DateFormatSymbols icuSymbols) {
icuSymbols.setAmPmStrings(value.getAmPmStrings());
icuSymbols.setEras(value.getEras());
icuSymbols.setLocalPatternChars(value.getLocalPatternChars());
icuSymbols.setMonths(value.getMonths());
icuSymbols.setShortMonths(value.getShortMonths());
icuSymbols.setShortWeekdays(value.getShortWeekdays());
icuSymbols.setWeekdays(value.getWeekdays());
icuSymbols.setZoneStrings(value.getZoneStrings());
}
public SimpleDateFormat(String template, TLocale locale) {
this(locale);
validatePattern(template);
icuFormat = new com.ibm.icu.text.SimpleDateFormat(template, locale);
icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
pattern = template;
formatData = new DateFormatSymbols(locale, icuFormat.getDateFormatSymbols());
}
SimpleDateFormat(TLocale locale, com.ibm.icu.text.SimpleDateFormat icuFormat) {
this(locale);
this.icuFormat = icuFormat;
this.icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
pattern = (String) Format.getInternalField("pattern", icuFormat);
formatData = new DateFormatSymbols(locale);
}
private SimpleDateFormat(TLocale locale) {
numberFormat = NumberFormat.getInstance(locale);
numberFormat.setParseIntegerOnly(true);
numberFormat.setGroupingUsed(false);
calendar = new GregorianCalendar(locale);
calendar.add(Calendar.YEAR, -80);
tzId = calendar.getTimeZone().getID();
creationYear = calendar.get(Calendar.YEAR);
defaultCenturyStart = calendar.getTime();
}
public void applyLocalizedPattern(String template) {
icuFormat.applyLocalizedPattern(template);
pattern = icuFormat.toPattern();
}
public void applyPattern(String template) {
validatePattern(template);
/*
* ICU spec explicitly mentions that "ICU interprets a single 'y'
* differently than Java." We need to do a trick here to follow Java
* spec.
*/
String templateForICU = patternForICU(template);
icuFormat.applyPattern(templateForICU);
pattern = template;
}
@SuppressWarnings("nls")
private String patternForICU(String p) {
String[] subPatterns = p.split("'");
boolean quote = false;
boolean first = true;
StringBuilder result = new StringBuilder();
for (String subPattern : subPatterns) {
if (!quote) {
// replace 'y' with 'yy' for ICU to follow Java spec
result.append((first ? "" : "'") + subPattern.replaceAll("(?<!y)y(?!y)", "yy"));
first = false;
} else {
result.append("'" + subPattern);
}
quote = !quote;
}
if (p.endsWith("'")) {
result.append("'");
}
return result.toString();
}
@Override
public Object clone() {
SimpleDateFormat clone = (SimpleDateFormat) super.clone();
clone.formatData = (DateFormatSymbols) formatData.clone();
clone.defaultCenturyStart = new Date(defaultCenturyStart.getTime());
clone.tzId = tzId;
return clone;
}
@Override
public boolean equals(Object object) {
if (this == object) {
return true;
}
if (!(object instanceof SimpleDateFormat)) {
return false;
}
SimpleDateFormat simple = (SimpleDateFormat) object;
return super.equals(object) && pattern.equals(simple.pattern) && formatData.equals(simple.formatData);
}
@Override
public AttributedCharacterIterator formatToCharacterIterator(Object object) {
if (object == null) {
throw new NullPointerException();
}
if (object instanceof Date) {
return formatToCharacterIteratorImpl((Date) object);
}
if (object instanceof Number) {
return formatToCharacterIteratorImpl(new Date(((Number) object).longValue()));
}
throw new IllegalArgumentException();
}
private AttributedCharacterIterator formatToCharacterIteratorImpl(Date date) {
StringBuffer buffer = new StringBuffer();
TList<FieldPosition> fields = new TArrayList<>();
// format the date, and find fields
formatImpl(date, buffer, null, fields);
// create and AttributedString with the formatted buffer
AttributedString as = new AttributedString(buffer.toString());
// add DateFormat field attributes to the AttributedString
for (int i = 0; i < fields.size(); i++) {
FieldPosition pos = fields.get(i);
Format.Field attribute = pos.getFieldAttribute();
as.addAttribute(attribute, attribute, pos.getBeginIndex(), pos.getEndIndex());
}
// return the CharacterIterator from AttributedString
return as.getIterator();
}
private StringBuffer formatImpl(Date date, StringBuffer buffer, FieldPosition field, TList<FieldPosition> fields) {
boolean quote = false;
int next, last = -1, count = 0;
calendar.setTime(date);
if (field != null) {
field.clear();
}
final int patternLength = pattern.length();
for (int i = 0; i < patternLength; i++) {
next = (pattern.charAt(i));
if (next == '\'') {
if (count > 0) {
append(buffer, field, fields, (char) last, count);
count = 0;
}
if (last == next) {
buffer.append('\'');
last = -1;
} else {
last = next;
}
quote = !quote;
continue;
}
if (!quote && (last == next || (next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z'))) {
if (last == next) {
count++;
} else {
if (count > 0) {
append(buffer, field, fields, (char) last, count);
}
last = next;
count = 1;
}
} else {
if (count > 0) {
append(buffer, field, fields, (char) last, count);
count = 0;
}
last = -1;
buffer.append((char) next);
}
}
if (count > 0) {
append(buffer, field, fields, (char) last, count);
}
return buffer;
}
private void append(StringBuffer buffer, FieldPosition position, TList<FieldPosition> fields, char format, int count) {
int field = -1;
int index = patternChars.indexOf(format);
if (index == -1) {
throw new IllegalArgumentException("Unknown pattern character - " + format);
}
int beginPosition = buffer.length();
Field dateFormatField = null;
switch (index) {
case ERA_FIELD:
dateFormatField = Field.ERA;
buffer.append(formatData.eras[calendar.get(Calendar.ERA)]);
break;
case YEAR_FIELD:
dateFormatField = Field.YEAR;
int year = calendar.get(Calendar.YEAR);
if (count < 4) {
appendNumber(buffer, 2, year % 100);
} else {
appendNumber(buffer, count, year);
}
break;
case MONTH_FIELD:
dateFormatField = Field.MONTH;
int month = calendar.get(Calendar.MONTH);
if (count <= 2) {
appendNumber(buffer, count, month + 1);
} else if (count == 3) {
buffer.append(formatData.shortMonths[month]);
} else {
buffer.append(formatData.months[month]);
}
break;
case DATE_FIELD:
dateFormatField = Field.DAY_OF_MONTH;
field = Calendar.DATE;
break;
case HOUR_OF_DAY1_FIELD: // k
dateFormatField = Field.HOUR_OF_DAY1;
int hour = calendar.get(Calendar.HOUR_OF_DAY);
appendNumber(buffer, count, hour == 0 ? 24 : hour);
break;
case HOUR_OF_DAY0_FIELD: // H
dateFormatField = Field.HOUR_OF_DAY0;
field = Calendar.HOUR_OF_DAY;
break;
case MINUTE_FIELD:
dateFormatField = Field.MINUTE;
field = Calendar.MINUTE;
break;
case SECOND_FIELD:
dateFormatField = Field.SECOND;
field = Calendar.SECOND;
break;
case MILLISECOND_FIELD:
dateFormatField = Field.MILLISECOND;
int value = calendar.get(Calendar.MILLISECOND);
appendNumber(buffer, count, value);
break;
case DAY_OF_WEEK_FIELD:
dateFormatField = Field.DAY_OF_WEEK;
int day = calendar.get(Calendar.DAY_OF_WEEK);
if (count < 4) {
buffer.append(formatData.shortWeekdays[day]);
} else {
buffer.append(formatData.weekdays[day]);
}
break;
case DAY_OF_YEAR_FIELD:
dateFormatField = Field.DAY_OF_YEAR;
field = Calendar.DAY_OF_YEAR;
break;
case DAY_OF_WEEK_IN_MONTH_FIELD:
dateFormatField = Field.DAY_OF_WEEK_IN_MONTH;
field = Calendar.DAY_OF_WEEK_IN_MONTH;
break;
case WEEK_OF_YEAR_FIELD:
dateFormatField = Field.WEEK_OF_YEAR;
field = Calendar.WEEK_OF_YEAR;
break;
case WEEK_OF_MONTH_FIELD:
dateFormatField = Field.WEEK_OF_MONTH;
field = Calendar.WEEK_OF_MONTH;
break;
case AM_PM_FIELD:
dateFormatField = Field.AM_PM;
buffer.append(formatData.ampms[calendar.get(Calendar.AM_PM)]);
break;
case HOUR1_FIELD: // h
dateFormatField = Field.HOUR1;
hour = calendar.get(Calendar.HOUR);
appendNumber(buffer, count, hour == 0 ? 12 : hour);
break;
case HOUR0_FIELD: // K
dateFormatField = Field.HOUR0;
field = Calendar.HOUR;
break;
case TIMEZONE_FIELD: // z
dateFormatField = Field.TIME_ZONE;
appendTimeZone(buffer, count, true);
break;
case com.ibm.icu.text.DateFormat.TIMEZONE_RFC_FIELD: // Z
dateFormatField = Field.TIME_ZONE;
appendTimeZone(buffer, count, false);
break;
}
if (field != -1) {
appendNumber(buffer, count, calendar.get(field));
}
if (fields != null) {
position = new FieldPosition(dateFormatField);
position.setBeginIndex(beginPosition);
position.setEndIndex(buffer.length());
fields.add(position);
} else {
// Set to the first occurrence
if ((position.getFieldAttribute() == dateFormatField || (position.getFieldAttribute() == null && position
.getField() == index)) && position.getEndIndex() == 0) {
position.setBeginIndex(beginPosition);
position.setEndIndex(buffer.length());
}
}
}
private void appendTimeZone(StringBuffer buffer, int count, boolean generalTimezone) {
// cannot call TimeZone.getDisplayName() because it would not use
// the DateFormatSymbols of this SimpleDateFormat
if (generalTimezone) {
String id = calendar.getTimeZone().getID();
String[][] zones = formatData.getZoneStrings();
String[] zone = null;
for (String[] element : zones) {
if (id.equals(element[0])) {
zone = element;
break;
}
}
if (zone == null) {
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
char sign = '+';
if (offset < 0) {
sign = '-';
offset = -offset;
}
buffer.append("GMT");
buffer.append(sign);
appendNumber(buffer, 2, offset / 3600000);
buffer.append(':');
appendNumber(buffer, 2, (offset % 3600000) / 60000);
} else {
int daylight = calendar.get(Calendar.DST_OFFSET) == 0 ? 0 : 2;
if (count < 4) {
buffer.append(zone[2 + daylight]);
} else {
buffer.append(zone[1 + daylight]);
}
}
} else {
int offset = calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET);
char sign = '+';
if (offset < 0) {
sign = '-';
offset = -offset;
}
buffer.append(sign);
appendNumber(buffer, 2, offset / 3600000);
appendNumber(buffer, 2, (offset % 3600000) / 60000);
}
}
private void appendNumber(StringBuffer buffer, int count, int value) {
int minimumIntegerDigits = numberFormat.getMinimumIntegerDigits();
numberFormat.setMinimumIntegerDigits(count);
numberFormat.format(new Integer(value), buffer, new FieldPosition(0));
numberFormat.setMinimumIntegerDigits(minimumIntegerDigits);
}
@Override
public StringBuffer format(Date date, StringBuffer buffer, FieldPosition fieldPos) {
String id = calendar.getTimeZone().getID();
if (!tzId.equals(id)) {
tzId = id;
icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
}
// As ICU has its own implementation for DateFormat.Field, we need to
// pass an ICU instance of DateFormat.Field to the FieldPosition to get
// the begin and end index.
StringBuffer result = null;
Format.Field attribute = fieldPos.getFieldAttribute();
if (attribute instanceof DateFormat.Field) {
com.ibm.icu.text.DateFormat.Field icuAttribute = toICUField((DateFormat.Field) attribute);
int field = fieldPos.getField();
FieldPosition icuFieldPos = new FieldPosition(icuAttribute, field);
result = icuFormat.format(date, buffer, icuFieldPos);
fieldPos.setBeginIndex(icuFieldPos.getBeginIndex());
fieldPos.setEndIndex(icuFieldPos.getEndIndex());
return result;
}
return icuFormat.format(date, buffer, fieldPos);
}
private com.ibm.icu.text.DateFormat.Field toICUField(DateFormat.Field attribute) {
com.ibm.icu.text.DateFormat.Field icuAttribute = null;
if (attribute == DateFormat.Field.ERA) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.ERA;
} else if (attribute == DateFormat.Field.YEAR) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.YEAR;
} else if (attribute == DateFormat.Field.MONTH) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.MONTH;
} else if (attribute == DateFormat.Field.HOUR_OF_DAY0) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR_OF_DAY0;
} else if (attribute == DateFormat.Field.HOUR_OF_DAY1) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR_OF_DAY1;
} else if (attribute == DateFormat.Field.MINUTE) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.MINUTE;
} else if (attribute == DateFormat.Field.SECOND) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.SECOND;
} else if (attribute == DateFormat.Field.MILLISECOND) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.MILLISECOND;
} else if (attribute == DateFormat.Field.DAY_OF_WEEK) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_WEEK;
} else if (attribute == DateFormat.Field.DAY_OF_MONTH) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_MONTH;
} else if (attribute == DateFormat.Field.DAY_OF_YEAR) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_YEAR;
} else if (attribute == DateFormat.Field.DAY_OF_WEEK_IN_MONTH) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.DAY_OF_WEEK_IN_MONTH;
} else if (attribute == DateFormat.Field.WEEK_OF_YEAR) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.WEEK_OF_YEAR;
} else if (attribute == DateFormat.Field.WEEK_OF_MONTH) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.WEEK_OF_MONTH;
} else if (attribute == DateFormat.Field.AM_PM) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.AM_PM;
} else if (attribute == DateFormat.Field.HOUR0) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR0;
} else if (attribute == DateFormat.Field.HOUR1) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.HOUR1;
} else if (attribute == DateFormat.Field.TIME_ZONE) {
icuAttribute = com.ibm.icu.text.DateFormat.Field.TIME_ZONE;
}
return icuAttribute;
}
public Date get2DigitYearStart() {
return defaultCenturyStart;
}
public DateFormatSymbols getDateFormatSymbols() {
// Return a clone so the arrays in the ResourceBundle are not modified
return (DateFormatSymbols) formatData.clone();
}
@Override
public int hashCode() {
return super.hashCode() + pattern.hashCode() + formatData.hashCode() + creationYear;
}
@Override
public Date parse(String string, ParsePosition position) {
String id = calendar.getTimeZone().getID();
if (!tzId.equals(id)) {
tzId = id;
icuFormat.setTimeZone(com.ibm.icu.util.TimeZone.getTimeZone(tzId));
}
icuFormat.setLenient(calendar.isLenient());
return icuFormat.parse(string, position);
}
public void set2DigitYearStart(Date date) {
icuFormat.set2DigitYearStart(date);
defaultCenturyStart = date;
Calendar cal = new GregorianCalendar();
cal.setTime(date);
creationYear = cal.get(Calendar.YEAR);
}
public void setDateFormatSymbols(DateFormatSymbols value) {
com.ibm.icu.text.DateFormatSymbols icuSymbols = new com.ibm.icu.text.DateFormatSymbols();
copySymbols(value, icuSymbols);
icuFormat.setDateFormatSymbols(icuSymbols);
formatData = (DateFormatSymbols) value.clone();
}
public String toLocalizedPattern() {
return icuFormat.toLocalizedPattern();
}
public String toPattern() {
return pattern;
}
}

View File

@ -32,12 +32,12 @@
package org.teavm.classlib.java.util;
import java.text.DateFormat;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import org.teavm.classlib.java.io.TSerializable;
import org.teavm.classlib.java.lang.TCloneable;
import org.teavm.classlib.java.lang.TComparable;
import org.teavm.classlib.java.text.DateFormat;
import org.teavm.classlib.java.text.DateFormatSymbols;
import org.teavm.classlib.java.text.SimpleDateFormat;
public class Date implements TSerializable, TCloneable, TComparable<Date> {
@ -104,6 +104,7 @@ public class Date implements TSerializable, TCloneable, TComparable<Date> {
}
}
@Override
public int compareTo(Date date) {
if (milliseconds < date.milliseconds) {
return -1;

View File

@ -271,20 +271,6 @@ public abstract class TimeZone implements TSerializable, TCloneable {
private static void setICUDefaultTimeZone(TimeZone timezone) {
final com.ibm.icu.util.TimeZone icuTZ = com.ibm.icu.util.TimeZone.getTimeZone(timezone.getID());
AccessController.doPrivileged(new PrivilegedAction<java.lang.reflect.Field>() {
public java.lang.reflect.Field run() {
java.lang.reflect.Field field = null;
try {
field = com.ibm.icu.util.TimeZone.class.getDeclaredField("defaultZone");
field.setAccessible(true);
field.set("defaultZone", icuTZ);
} catch (Exception e) {
return null;
}
return field;
}
});
}
public void setID(String name) {