This commit is contained in:
Lana Steuck 2014-02-24 12:57:31 -08:00
commit 3330a1f7a6
5 changed files with 1146 additions and 867 deletions

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@ package com.sun.org.apache.xalan.internal.xsltc.compiler;
import java.util.Vector;
import com.sun.org.apache.bcel.internal.generic.ConstantPoolGen;
import com.sun.org.apache.bcel.internal.generic.INVOKEVIRTUAL;
import com.sun.org.apache.bcel.internal.generic.INVOKESTATIC;
import com.sun.org.apache.bcel.internal.generic.InstructionList;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.ClassGenerator;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.MethodGenerator;
@ -51,7 +51,8 @@ final class StringLengthCall extends FunctionCall {
il.append(methodGen.loadContextNode());
Type.Node.translateTo(classGen, methodGen, Type.String);
}
il.append(new INVOKEVIRTUAL(cpg.addMethodref(STRING_CLASS,
"length", "()I")));
il.append(new INVOKESTATIC(cpg.addMethodref(BASIS_LIBRARY_CLASS,
"getStringLength",
"(Ljava/lang/String;)I")));
}
}

View File

@ -1660,5 +1660,14 @@ public final class BasisLibrary {
}
/**
* Utility method to calculate string-length as a number of code points,
* to avoid possible errors with string that contains
* complementary characters
*/
public static int getStringLength(String str) {
return str.codePointCount(0,str.length());
}
//-- End utility functions
}

View File

@ -3,11 +3,12 @@
* DO NOT REMOVE OR ALTER!
*/
/*
* Copyright 2005 The Apache Software Foundation.
*
* Licensed 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
* 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
*
@ -106,24 +107,20 @@ class DurationImpl
extends Duration
implements Serializable {
/**
* <p>Number of Fields.</p>
*/
private static final int FIELD_NUM = 6;
/**
* <p>Internal array of value Fields.</p>
*/
private static final DatatypeConstants.Field[] FIELDS = new DatatypeConstants.Field[]{
DatatypeConstants.YEARS,
DatatypeConstants.MONTHS,
DatatypeConstants.DAYS,
DatatypeConstants.HOURS,
DatatypeConstants.MINUTES,
DatatypeConstants.SECONDS
};
private static final DatatypeConstants.Field[] FIELDS = new DatatypeConstants.Field[]{
DatatypeConstants.YEARS,
DatatypeConstants.MONTHS,
DatatypeConstants.DAYS,
DatatypeConstants.HOURS,
DatatypeConstants.MINUTES,
DatatypeConstants.SECONDS
};
/**
/**
* <p>Internal array of value Field ids.</p>
*/
private static final int[] FIELD_IDS = {
@ -141,9 +138,9 @@ class DurationImpl
private static final TimeZone GMT = TimeZone.getTimeZone("GMT");
/**
* <p>BigDecimal value of 0.</p>
*/
private static final BigDecimal ZERO = BigDecimal.valueOf((long) 0);
* <p>BigDecimal value of 0.</p>
*/
private static final BigDecimal ZERO = BigDecimal.valueOf(0);
/**
* <p>Indicates the sign. -1, 0 or 1 if the duration is negative,
@ -186,17 +183,17 @@ class DurationImpl
*/
protected BigDecimal seconds;
/**
* Returns the sign of this duration in -1,0, or 1.
*
* @return
* -1 if this duration is negative, 0 if the duration is zero,
* and 1 if the duration is postive.
*/
public int getSign() {
/**
* Returns the sign of this duration in -1,0, or 1.
*
* @return
* -1 if this duration is negative, 0 if the duration is zero,
* and 1 if the duration is postive.
*/
public int getSign() {
return signum;
}
return signum;
}
/**
* TODO: Javadoc
@ -206,20 +203,20 @@ class DurationImpl
*/
protected int calcSignum(boolean isPositive) {
if ((years == null || years.signum() == 0)
&& (months == null || months.signum() == 0)
&& (days == null || days.signum() == 0)
&& (hours == null || hours.signum() == 0)
&& (minutes == null || minutes.signum() == 0)
&& (seconds == null || seconds.signum() == 0)) {
&& (months == null || months.signum() == 0)
&& (days == null || days.signum() == 0)
&& (hours == null || hours.signum() == 0)
&& (minutes == null || minutes.signum() == 0)
&& (seconds == null || seconds.signum() == 0)) {
return 0;
}
if (isPositive) {
return 1;
} else {
return -1;
}
}
if (isPositive) {
return 1;
}
else {
return -1;
}
}
/**
@ -357,7 +354,7 @@ class DurationImpl
}
// int -> BigInteger
return new BigInteger(String.valueOf(i));
return BigInteger.valueOf(i);
}
/**
@ -373,14 +370,16 @@ class DurationImpl
if (l > 0) {
signum = 1;
} else if (l < 0) {
}
else if (l < 0) {
signum = -1;
if (l == 0x8000000000000000L) {
// negating 0x8000000000000000L causes an overflow
l++;
}
l *= -1;
} else {
}
else {
signum = 0;
}
@ -454,21 +453,22 @@ class DurationImpl
throws IllegalArgumentException {
// only if I could use the JDK1.4 regular expression ....
if (lexicalRepresentation == null) {
throw new NullPointerException();
}
final String s = lexicalRepresentation;
boolean positive;
int[] idx = new int[1];
int length = s.length();
boolean timeRequired = false;
if (lexicalRepresentation == null) {
throw new NullPointerException();
}
idx[0] = 0;
if (length != idx[0] && s.charAt(idx[0]) == '-') {
idx[0]++;
positive = false;
} else {
}
else {
positive = true;
}
@ -484,8 +484,8 @@ class DurationImpl
String[] dateParts = new String[3];
int[] datePartsIndex = new int[3];
while (length != idx[0]
&& isDigit(s.charAt(idx[0]))
&& dateLen < 3) {
&& isDigit(s.charAt(idx[0]))
&& dateLen < 3) {
datePartsIndex[dateLen] = idx[0];
dateParts[dateLen++] = parsePiece(s, idx);
}
@ -493,7 +493,8 @@ class DurationImpl
if (length != idx[0]) {
if (s.charAt(idx[0]++) == 'T') {
timeRequired = true;
} else {
}
else {
throw new IllegalArgumentException(s); // ,idx[0]-1);
}
}
@ -502,8 +503,8 @@ class DurationImpl
String[] timeParts = new String[3];
int[] timePartsIndex = new int[3];
while (length != idx[0]
&& isDigitOrPeriod(s.charAt(idx[0]))
&& timeLen < 3) {
&& isDigitOrPeriod(s.charAt(idx[0]))
&& timeLen < 3) {
timePartsIndex[timeLen] = idx[0];
timeParts[timeLen++] = parsePiece(s, idx);
}
@ -604,6 +605,9 @@ class DurationImpl
int idx = tokens.length();
for (int i = len - 1; i >= 0; i--) {
if (parts[i] == null) {
throw new IllegalArgumentException(whole);
}
int nidx =
tokens.lastIndexOf(
parts[i].charAt(parts[i].length() - 1),
@ -722,8 +726,7 @@ class DurationImpl
*/
public int compare(Duration rhs) {
BigInteger maxintAsBigInteger = BigInteger.valueOf((long) Integer.MAX_VALUE);
BigInteger minintAsBigInteger = BigInteger.valueOf((long) Integer.MIN_VALUE);
BigInteger maxintAsBigInteger = BigInteger.valueOf(Integer.MAX_VALUE);
// check for fields that are too large in this Duration
if (years != null && years.compareTo(maxintAsBigInteger) == 1) {
@ -778,7 +781,7 @@ class DurationImpl
if (seconds != null && seconds.toBigInteger().compareTo(maxintAsBigInteger) == 1) {
throw new UnsupportedOperationException(
DatatypeMessageFormatter.formatMessage(null, "TooLarge",
new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), seconds.toString()})
new Object[]{this.getClass().getName() + "#compare(Duration duration)" + DatatypeConstants.SECONDS.toString(), toString(seconds)})
//this.getClass().getName() + "#compare(Duration duration)"
//+ " seconds too large to be supported by this implementation "
@ -957,9 +960,9 @@ class DurationImpl
return resultA;
}
private int compareResults(int resultA, int resultB){
private int compareResults(int resultA, int resultB) {
if ( resultB == DatatypeConstants.INDETERMINATE ) {
if ( resultB == DatatypeConstants.INDETERMINATE ) {
return DatatypeConstants.INDETERMINATE;
}
else if ( resultA!=resultB) {
@ -1007,25 +1010,25 @@ class DurationImpl
buf.append('P');
if (years != null) {
buf.append(years + "Y");
buf.append(years).append('Y');
}
if (months != null) {
buf.append(months + "M");
buf.append(months).append('M');
}
if (days != null) {
buf.append(days + "D");
buf.append(days).append('D');
}
if (hours != null || minutes != null || seconds != null) {
buf.append('T');
if (hours != null) {
buf.append(hours + "H");
buf.append(hours).append('H');
}
if (minutes != null) {
buf.append(minutes + "M");
buf.append(minutes).append('M');
}
if (seconds != null) {
buf.append(toString(seconds) + "S");
buf.append(toString(seconds)).append('S');
}
}
@ -1055,10 +1058,12 @@ class DurationImpl
int insertionPoint = intString.length() - scale;
if (insertionPoint == 0) { /* Point goes right before intVal */
return "0." + intString;
} else if (insertionPoint > 0) { /* Point goes inside intVal */
}
else if (insertionPoint > 0) { /* Point goes inside intVal */
buf = new StringBuffer(intString);
buf.insert(insertionPoint, '.');
} else { /* We must insert zeros between point and intVal */
}
else { /* We must insert zeros between point and intVal */
buf = new StringBuffer(3 - insertionPoint + intString.length());
buf.append("0.");
for (int i = 0; i < -insertionPoint; i++) {
@ -1302,7 +1307,8 @@ class DurationImpl
Number n = getField(field);
if (n == null) {
return 0;
} else {
}
else {
return n.intValue();
}
}
@ -1340,8 +1346,7 @@ class DurationImpl
public long getTimeInMillis(final Calendar startInstant) {
Calendar cal = (Calendar) startInstant.clone();
addTo(cal);
return getCalendarTimeInMillis(cal)
- getCalendarTimeInMillis(startInstant);
return getCalendarTimeInMillis(cal) - getCalendarTimeInMillis(startInstant);
}
/**
@ -1451,13 +1456,13 @@ class DurationImpl
int days = (int) (diff / (1000L * 60L * 60L * 24L));
return new DurationImpl(
days >= 0,
null,
null,
wrap(Math.abs(days)),
(BigInteger) getField(DatatypeConstants.HOURS),
(BigInteger) getField(DatatypeConstants.MINUTES),
(BigDecimal) getField(DatatypeConstants.SECONDS));
days >= 0,
null,
null,
wrap(Math.abs(days)),
(BigInteger) getField(DatatypeConstants.HOURS),
(BigInteger) getField(DatatypeConstants.MINUTES),
(BigDecimal) getField(DatatypeConstants.SECONDS));
}
/**
@ -1547,14 +1552,16 @@ class DurationImpl
} else {
carry = ZERO;
}
} else {
}
else {
carry = bd.multiply(FACTORS[i]);
}
}
if (seconds != null) {
buf[5] = seconds.multiply(factor).add(carry);
} else {
}
else {
buf[5] = carry;
}
@ -1581,14 +1588,17 @@ class DurationImpl
if (f == DatatypeConstants.SECONDS) {
if (seconds != null) {
return seconds;
} else {
}
else {
return ZERO;
}
} else {
}
else {
BigInteger bi = (BigInteger) getField(f);
if (bi == null) {
return ZERO;
} else {
}
else {
return new BigDecimal(bi);
}
}
@ -1607,7 +1617,8 @@ class DurationImpl
boolean canBeNull) {
if (canBeNull && value.signum() == 0) {
return null;
} else {
}
else {
return value.unscaledValue();
}
}
@ -1616,7 +1627,7 @@ class DurationImpl
* 1 unit of FIELDS[i] is equivalent to <code>FACTORS[i]</code> unit of
* FIELDS[i+1].
*/
private static final BigDecimal[] FACTORS = new BigDecimal[]{
private static final BigDecimal[] FACTORS = new BigDecimal[] {
BigDecimal.valueOf(12),
null/*undefined*/,
BigDecimal.valueOf(24),
@ -1963,11 +1974,21 @@ class DurationImpl
date.setTime(getCalendarTimeInMillis(cal));
}
/**
* Returns time value in milliseconds
* @param cal A calendar object
* @return time value
*
* Diff from Xerces; Use JDK 1.5 feature.
*/
private static long getCalendarTimeInMillis(Calendar cal) {
return cal.getTimeInMillis();
}
/**
* <p>Stream Unique Identifier.</p>
*
* <p>TODO: Serialization should use the XML string representation as
* the serialization format to ensure future compatibility.</p>
* <p>Serialization uses the lexical form returned by toString().</p>
*/
private static final long serialVersionUID = 1L;
@ -1996,25 +2017,10 @@ class DurationImpl
}
private Object readResolve() throws ObjectStreamException {
// try {
return new DurationImpl(lexical);
// } catch( ParseException e ) {
// throw new StreamCorruptedException("unable to parse "+lexical+" as duration");
// }
}
private static final long serialVersionUID = 1L;
}
/**
* Calls the {@link Calendar#getTimeInMillis} method.
* Prior to JDK1.4, this method was protected and therefore
* cannot be invoked directly.
*
* In future, this should be replaced by
* <code>cal.getTimeInMillis()</code>
*/
private static long getCalendarTimeInMillis(Calendar cal) {
return cal.getTime().getTime();
}
}

View File

@ -25,6 +25,8 @@
package com.sun.org.apache.xerces.internal.jaxp.datatype;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
@ -195,6 +197,17 @@ public class XMLGregorianCalendarImpl
extends XMLGregorianCalendar
implements Serializable, Cloneable {
/** Backup values **/
transient private BigInteger orig_eon;
transient private int orig_year = DatatypeConstants.FIELD_UNDEFINED;
transient private int orig_month = DatatypeConstants.FIELD_UNDEFINED;
transient private int orig_day = DatatypeConstants.FIELD_UNDEFINED;
transient private int orig_hour = DatatypeConstants.FIELD_UNDEFINED;
transient private int orig_minute = DatatypeConstants.FIELD_UNDEFINED;
transient private int orig_second = DatatypeConstants.FIELD_UNDEFINED;
transient private BigDecimal orig_fracSeconds;
transient private int orig_timezone = DatatypeConstants.FIELD_UNDEFINED;
/**
* <p>Eon of this <code>XMLGregorianCalendar</code>.</p>
*/
@ -241,9 +254,14 @@ public class XMLGregorianCalendarImpl
private BigDecimal fractionalSecond = null;
/**
* <p>Constant to represent a billion.</p>
* <p>BigInteger constant; representing a billion.</p>
*/
private static final BigInteger BILLION = new BigInteger("1000000000");
private static final BigInteger BILLION_B = new BigInteger("1000000000");
/**
* <p>int constant; representing a billion.</p>
*/
private static final int BILLION_I = 1000000000;
/**
* <p>Obtain a pure Gregorian Calendar by calling
@ -441,6 +459,23 @@ public class XMLGregorianCalendarImpl
//"\"" + lexicalRepresentation + "\" is not a valid representation of an XML Gregorian Calendar value."
);
}
save();
}
/**
* save original values
*/
private void save() {
orig_eon = eon;
orig_year = year;
orig_month = month;
orig_day = day;
orig_hour = hour;
orig_minute = minute;
orig_second = second;
orig_fracSeconds = fractionalSecond;
orig_timezone = timezone;
}
/**
@ -479,14 +514,14 @@ public class XMLGregorianCalendarImpl
BigDecimal fractionalSecond,
int timezone) {
setYear(year);
setYear(year);
setMonth(month);
setDay(day);
setTime(hour, minute, second, fractionalSecond);
setTimezone(timezone);
setTimezone(timezone);
// check for validity
if (!isValid()) {
// check for validity
if (!isValid()) {
throw new IllegalArgumentException(
DatatypeMessageFormatter.formatMessage(null,
@ -519,8 +554,9 @@ public class XMLGregorianCalendarImpl
);
*/
}
}
save();
}
/**
@ -547,17 +583,21 @@ public class XMLGregorianCalendarImpl
int hour,
int minute,
int second,
int millisecond,
int millisecond,
int timezone) {
setYear(year);
setYear(year);
setMonth(month);
setDay(day);
setTime(hour, minute, second);
setTimezone(timezone);
setMillisecond(millisecond);
setTimezone(timezone);
BigDecimal realMilliseconds = null;
if (millisecond != DatatypeConstants.FIELD_UNDEFINED) {
realMilliseconds = BigDecimal.valueOf(millisecond, 3);
}
setFractionalSecond(realMilliseconds);
if (!isValid()) {
if (!isValid()) {
throw new IllegalArgumentException(
DatatypeMessageFormatter.formatMessage(null,
@ -580,7 +620,9 @@ public class XMLGregorianCalendarImpl
);
*/
}
}
save();
}
/**
@ -661,6 +703,7 @@ public class XMLGregorianCalendarImpl
// Calendar ZONE_OFFSET and DST_OFFSET fields are in milliseconds.
int offsetInMinutes = (cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / (60 * 1000);
this.setTimezone(offsetInMinutes);
save();
}
// Factories
@ -1164,7 +1207,7 @@ public class XMLGregorianCalendarImpl
this.eon = null;
this.year = DatatypeConstants.FIELD_UNDEFINED;
} else {
BigInteger temp = year.remainder(BILLION);
BigInteger temp = year.remainder(BILLION_B);
this.year = temp.intValue();
setEon(year.subtract(temp));
}
@ -1187,12 +1230,13 @@ public class XMLGregorianCalendarImpl
if (year == DatatypeConstants.FIELD_UNDEFINED) {
this.year = DatatypeConstants.FIELD_UNDEFINED;
this.eon = null;
} else if (Math.abs(year) < BILLION.intValue()) {
}
else if (Math.abs(year) < BILLION_I) {
this.year = year;
this.eon = null;
} else {
BigInteger theYear = BigInteger.valueOf((long) year);
BigInteger remainder = theYear.remainder(BILLION);
BigInteger remainder = theYear.remainder(BILLION_B);
this.year = remainder.intValue();
setEon(theYear.subtract(remainder));
}
@ -1688,6 +1732,9 @@ public class XMLGregorianCalendarImpl
if (obj == null || !(obj instanceof XMLGregorianCalendar)) {
return false;
}
if (obj == this) {
return true;
}
return compare((XMLGregorianCalendar) obj) == DatatypeConstants.EQUAL;
}
@ -1950,51 +1997,36 @@ public class XMLGregorianCalendarImpl
// no need to check for anything except for constraints
// between fields.
//check if days in month is valid. Can be dependent on leap year.
if (getMonth() == DatatypeConstants.FEBRUARY) {
// years could not be set
int maxDays = 29;
if (eon == null) {
if(year!=DatatypeConstants.FIELD_UNDEFINED)
maxDays = maximumDayInMonthFor(year,getMonth());
} else {
BigInteger years = getEonAndYear();
if (years != null) {
maxDays = maximumDayInMonthFor(getEonAndYear(), DatatypeConstants.FEBRUARY);
// check if days in month is valid. Can be dependent on leap year.
if (month != DatatypeConstants.FIELD_UNDEFINED && day != DatatypeConstants.FIELD_UNDEFINED) {
if (year != DatatypeConstants.FIELD_UNDEFINED) {
if (eon == null) {
if (day > maximumDayInMonthFor(year, month)) {
return false;
}
}
else if (day > maximumDayInMonthFor(getEonAndYear(), month)) {
return false;
}
}
if (getDay() > maxDays) {
// Use 2000 as a default since it's a leap year.
else if (day > maximumDayInMonthFor(2000, month)) {
return false;
}
}
// http://www.w3.org/2001/05/xmlschema-errata#e2-45
if (getHour() == 24) {
if(getMinute() != 0) {
return false;
} else if (getSecond() != 0) {
return false;
}
if (hour == 24 && (minute != 0 || second != 0 ||
(fractionalSecond != null && fractionalSecond.compareTo(DECIMAL_ZERO) != 0))) {
return false;
}
// XML Schema 1.0 specification defines year value of zero as
// invalid. Allow this class to set year field to zero
// since XML Schema 1.0 errata states that lexical zero will
// be allowed in next version and treated as 1 B.C.E.
if (eon == null) {
// optimize check.
if (year == 0) {
return false;
}
} else {
BigInteger yearField = getEonAndYear();
if (yearField != null) {
int result = compareField(yearField, BigInteger.ZERO);
if (result == DatatypeConstants.EQUAL) {
return false;
}
}
if (eon == null && year == 0) {
return false;
}
return true;
}
@ -2213,7 +2245,7 @@ public class XMLGregorianCalendarImpl
int quotient;
if (endMonth < 0) {
endMonth = (13 - 1) + endMonth + 1;
quotient = new BigDecimal(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue();
quotient = BigDecimal.valueOf(intTemp - 1).divide(new BigDecimal(TWELVE), BigDecimal.ROUND_UP).intValue();
} else {
quotient = (intTemp - 1) / (13 - 1);
endMonth += 1;
@ -2259,18 +2291,20 @@ public class XMLGregorianCalendarImpl
private static final BigInteger SIXTY = BigInteger.valueOf(60);
private static final BigInteger TWENTY_FOUR = BigInteger.valueOf(24);
private static final BigInteger TWELVE = BigInteger.valueOf(12);
private static final BigDecimal DECIMAL_ZERO = new BigDecimal("0");
private static final BigDecimal DECIMAL_ONE = new BigDecimal("1");
private static final BigDecimal DECIMAL_SIXTY = new BigDecimal("60");
private static final BigDecimal DECIMAL_ZERO = BigDecimal.valueOf(0);
private static final BigDecimal DECIMAL_ONE = BigDecimal.valueOf(1);
private static final BigDecimal DECIMAL_SIXTY = BigDecimal.valueOf(60);
private static int daysInMonth[] = { 0, // XML Schema months start at 1.
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
private static class DaysInMonth {
private static final int [] table = { 0, // XML Schema months start at 1.
31, 28, 31, 30, 31, 30,
31, 31, 30, 31, 30, 31};
}
private static int maximumDayInMonthFor(BigInteger year, int month) {
if (month != DatatypeConstants.FEBRUARY) {
return daysInMonth[month];
return DaysInMonth.table[month];
} else {
if (year.mod(FOUR_HUNDRED).equals(BigInteger.ZERO) ||
(!year.mod(HUNDRED).equals(BigInteger.ZERO) &&
@ -2278,21 +2312,21 @@ public class XMLGregorianCalendarImpl
// is a leap year.
return 29;
} else {
return daysInMonth[month];
return DaysInMonth.table[month];
}
}
}
private static int maximumDayInMonthFor(int year, int month) {
if (month != DatatypeConstants.FEBRUARY) {
return daysInMonth[month];
return DaysInMonth.table[month];
} else {
if (((year % 400) == 0) ||
(((year % 100) != 0) && ((year % 4) == 0))) {
// is a leap year.
return 29;
} else {
return daysInMonth[DatatypeConstants.FEBRUARY];
return DaysInMonth.table[DatatypeConstants.FEBRUARY];
}
}
}
@ -2404,10 +2438,16 @@ public class XMLGregorianCalendarImpl
result.setGregorianChange(PURE_GREGORIAN_CHANGE);
// if year( and eon) are undefined, leave default Calendar values
BigInteger year = getEonAndYear();
if (year != null) {
result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, year.abs().intValue());
if (year != DatatypeConstants.FIELD_UNDEFINED) {
if (eon == null) {
result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, Math.abs(year));
}
else {
BigInteger eonAndYear = getEonAndYear();
result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, eonAndYear.abs().intValue());
}
}
// only set month if it is set
@ -2543,16 +2583,31 @@ public class XMLGregorianCalendarImpl
result.setGregorianChange(PURE_GREGORIAN_CHANGE);
// if year( and eon) are undefined, leave default Calendar values
BigInteger year = getEonAndYear();
if (year != null) {
result.set(Calendar.ERA, year.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, year.abs().intValue());
if (year != DatatypeConstants.FIELD_UNDEFINED) {
if (eon == null) {
result.set(Calendar.ERA, year < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, Math.abs(year));
}
else {
final BigInteger eonAndYear = getEonAndYear();
result.set(Calendar.ERA, eonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, eonAndYear.abs().intValue());
}
} else {
// use default if set
BigInteger defaultYear = (defaults != null) ? defaults.getEonAndYear() : null;
if (defaultYear != null) {
result.set(Calendar.ERA, defaultYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, defaultYear.abs().intValue());
if (defaults != null) {
final int defaultYear = defaults.getYear();
if (defaultYear != DatatypeConstants.FIELD_UNDEFINED) {
if (defaults.getEon() == null) {
result.set(Calendar.ERA, defaultYear < 0 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, Math.abs(defaultYear));
}
else {
final BigInteger defaultEonAndYear = defaults.getEonAndYear();
result.set(Calendar.ERA, defaultEonAndYear.signum() == -1 ? GregorianCalendar.BC : GregorianCalendar.AD);
result.set(Calendar.YEAR, defaultEonAndYear.abs().intValue());
}
}
}
}
@ -2562,7 +2617,7 @@ public class XMLGregorianCalendarImpl
result.set(Calendar.MONTH, month - 1);
} else {
// use default if set
int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
final int defaultMonth = (defaults != null) ? defaults.getMonth() : DatatypeConstants.FIELD_UNDEFINED;
if (defaultMonth != DatatypeConstants.FIELD_UNDEFINED) {
// Calendar.MONTH is zero based while XMLGregorianCalendar month field is not.
result.set(Calendar.MONTH, defaultMonth - 1);
@ -2574,7 +2629,7 @@ public class XMLGregorianCalendarImpl
result.set(Calendar.DAY_OF_MONTH, day);
} else {
// use default if set
int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
final int defaultDay = (defaults != null) ? defaults.getDay() : DatatypeConstants.FIELD_UNDEFINED;
if (defaultDay != DatatypeConstants.FIELD_UNDEFINED) {
result.set(Calendar.DAY_OF_MONTH, defaultDay);
}
@ -2596,7 +2651,7 @@ public class XMLGregorianCalendarImpl
result.set(Calendar.MINUTE, minute);
} else {
// use default if set
int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
final int defaultMinute = (defaults != null) ? defaults.getMinute() : DatatypeConstants.FIELD_UNDEFINED;
if (defaultMinute != DatatypeConstants.FIELD_UNDEFINED) {
result.set(Calendar.MINUTE, defaultMinute);
}
@ -2607,7 +2662,7 @@ public class XMLGregorianCalendarImpl
result.set(Calendar.SECOND, second);
} else {
// use default if set
int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
final int defaultSecond = (defaults != null) ? defaults.getSecond() : DatatypeConstants.FIELD_UNDEFINED;
if (defaultSecond != DatatypeConstants.FIELD_UNDEFINED) {
result.set(Calendar.SECOND, defaultSecond);
}
@ -2618,7 +2673,7 @@ public class XMLGregorianCalendarImpl
result.set(Calendar.MILLISECOND, getMillisecond());
} else {
// use default if set
BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
final BigDecimal defaultFractionalSecond = (defaults != null) ? defaults.getFractionalSecond() : null;
if (defaultFractionalSecond != null) {
result.set(Calendar.MILLISECOND, defaults.getMillisecond());
}
@ -2671,6 +2726,9 @@ public class XMLGregorianCalendarImpl
customTimezoneId.append(sign);
customTimezoneId.append(hour);
if (minutes != 0) {
if (minutes < 10) {
customTimezoneId.append('0');
}
customTimezoneId.append(minutes);
}
result = TimeZone.getTimeZone(customTimezoneId.toString());
@ -2718,7 +2776,7 @@ public class XMLGregorianCalendarImpl
if(millisecond<0 || 999<millisecond)
if(millisecond!=DatatypeConstants.FIELD_UNDEFINED)
invalidFieldValue(MILLISECOND, millisecond);
fractionalSecond = new BigDecimal((long) millisecond).movePointLeft(3);
fractionalSecond = BigDecimal.valueOf(millisecond, 3);
}
}
@ -2770,7 +2828,7 @@ public class XMLGregorianCalendarImpl
// seen meta character. we don't do error check against the format
switch (format.charAt(fidx++)) {
case 'Y' : // year
parseAndSetYear(4);
parseYear();
break;
case 'M' : // month
@ -2851,7 +2909,7 @@ public class XMLGregorianCalendarImpl
int n = 0;
char ch;
int vstart = vidx;
while (isDigit(ch=peek()) && (vidx - vstart) <= maxDigits) {
while (isDigit(ch=peek()) && (vidx - vstart) < maxDigits) {
vidx++;
n = n*10 + ch-'0';
}
@ -2863,38 +2921,30 @@ public class XMLGregorianCalendarImpl
return n;
}
private void parseAndSetYear(int minDigits)
throws IllegalArgumentException {
private void parseYear()
throws IllegalArgumentException {
int vstart = vidx;
int n = 0;
boolean neg = false;
int sign = 0;
// skip leading negative, if it exists
if (peek() == '-') {
vidx++;
neg = true;
sign = 1;
}
while(true) {
char ch = peek();
if(!isDigit(ch))
break;
while (isDigit(peek())) {
vidx++;
n = n*10 + ch-'0';
}
if ((vidx - vstart) < minDigits) {
final int digits = vidx - vstart - sign;
if (digits < 4) {
// we are expecting more digits
throw new IllegalArgumentException(value); //,vidx);
}
if(vidx-vstart<7) {
// definitely int only. I don't know the exact # of digits that can be in int,
// but as long as we can catch (0-9999) range, that should be enough.
if(neg) n = -n;
year = n;
eon = null;
} else {
setYear(new BigInteger(value.substring(vstart, vidx)));
final String yearString = value.substring(vstart, vidx);
if (digits < 10) {
setYear(Integer.parseInt(yearString));
}
else {
setYear(new BigInteger(yearString));
}
}
@ -2922,150 +2972,123 @@ public class XMLGregorianCalendarImpl
* Prints this object according to the format specification.
*
* <p>
* I wrote a custom format method for a particular format string to
* see if it improves the performance, but it didn't. So this interpreting
* approach isn't too bad.
*
* <p>
* StringBuffer -> StringBuilder change had a very visible impact.
* It almost cut the execution time to half, but unfortunately we can't use it
* because we need to run on JDK 1.3
* It almost cut the execution time to half.
* Diff from Xerces:
* Xerces use StringBuffer due to the requirement to support
* JDKs older than JDK 1.5
*/
private String format( String format ) {
char[] buf = new char[32];
int bufPtr = 0;
StringBuilder buf = new StringBuilder();
int fidx=0,flen=format.length();
while(fidx<flen) {
char fch = format.charAt(fidx++);
if(fch!='%') {// not a meta char
buf[bufPtr++] = fch;
buf.append(fch);
continue;
}
switch(format.charAt(fidx++)) {
case 'Y':
if(eon==null) {
// optimized path
int y = getYear();
if(y<0) {
buf[bufPtr++] = '-';
y = -y;
}
bufPtr = print4Number(buf,bufPtr,y);
} else {
String s = getEonAndYear().toString();
// reallocate the buffer now so that it has enough space
char[] n = new char[buf.length+s.length()];
System.arraycopy(buf,0,n,0,bufPtr);
buf = n;
for(int i=s.length();i<4;i++)
buf[bufPtr++] = '0';
s.getChars(0,s.length(),buf,bufPtr);
bufPtr += s.length();
}
break;
case 'M':
bufPtr = print2Number(buf,bufPtr,getMonth());
break;
case 'D':
bufPtr = print2Number(buf,bufPtr,getDay());
break;
case 'h':
bufPtr = print2Number(buf,bufPtr,getHour());
break;
case 'm':
bufPtr = print2Number(buf,bufPtr,getMinute());
break;
case 's':
bufPtr = print2Number(buf,bufPtr,getSecond());
if (getFractionalSecond() != null) {
// Note: toPlainString() isn't available before Java 1.5
String frac = getFractionalSecond().toString();
int pos = frac.indexOf("E-");
if (pos >= 0) {
String zeros = frac.substring(pos+2);
frac = frac.substring(0,pos);
pos = frac.indexOf(".");
if (pos >= 0) {
frac = frac.substring(0,pos) + frac.substring(pos+1);
case 'Y':
if (eon == null) {
int absYear = year;
if (absYear < 0) {
buf.append('-');
absYear = -year;
}
int count = Integer.parseInt(zeros);
if (count < 40) {
frac = "00000000000000000000000000000000000000000".substring(0,count-1) + frac;
} else {
// do it the hard way
while (count > 1) {
frac = "0" + frac;
count--;
}
printNumber(buf, absYear, 4);
}
else {
printNumber(buf, getEonAndYear(), 4);
}
break;
case 'M':
printNumber(buf,getMonth(),2);
break;
case 'D':
printNumber(buf,getDay(),2);
break;
case 'h':
printNumber(buf,getHour(),2);
break;
case 'm':
printNumber(buf,getMinute(),2);
break;
case 's':
printNumber(buf,getSecond(),2);
if (getFractionalSecond() != null) {
//Xerces uses a custom method toString instead of
//toPlainString() since it needs to support JDKs older than 1.5
String frac = getFractionalSecond().toPlainString();
//skip leading zero.
buf.append(frac.substring(1, frac.length()));
}
break;
case 'z':
int offset = getTimezone();
if (offset == 0) {
buf.append('Z');
}
else if (offset != DatatypeConstants.FIELD_UNDEFINED) {
if (offset < 0) {
buf.append('-');
offset *= -1;
}
frac = "0." + frac;
else {
buf.append('+');
}
printNumber(buf,offset/60,2);
buf.append(':');
printNumber(buf,offset%60,2);
}
// reallocate the buffer now so that it has enough space
char[] n = new char[buf.length+frac.length()];
System.arraycopy(buf,0,n,0,bufPtr);
buf = n;
//skip leading zero.
frac.getChars(1, frac.length(), buf, bufPtr);
bufPtr += frac.length()-1;
}
break;
case 'z':
int offset = getTimezone();
if (offset == 0) {
buf[bufPtr++] = 'Z';
} else
if (offset != DatatypeConstants.FIELD_UNDEFINED) {
if (offset < 0) {
buf[bufPtr++] = '-';
offset *= -1;
} else {
buf[bufPtr++] = '+';
}
bufPtr = print2Number(buf, bufPtr, offset / 60);
buf[bufPtr++] = ':';
bufPtr = print2Number(buf, bufPtr, offset % 60);
}
break;
default:
throw new InternalError(); // impossible
break;
default:
throw new InternalError(); // impossible
}
}
return new String(buf,0,bufPtr);
return buf.toString();
}
/**
* Prints an int as two digits into the buffer.
* Prints an integer as a String.
*
* @param out
* The formatted string will be appended into this buffer.
* @param number
* Number to be printed. Must be positive.
* The integer to be printed.
* @param nDigits
* The field will be printed by using at least this
* number of digits. For example, 5 will be printed as "0005"
* if nDigits==4.
*/
private int print2Number( char[] out, int bufptr, int number ) {
out[bufptr++] = (char) ('0'+(number/10));
out[bufptr++] = (char) ('0'+(number%10));
return bufptr;
private void printNumber( StringBuilder out, int number, int nDigits ) {
String s = String.valueOf(number);
for (int i = s.length(); i < nDigits; i++) {
out.append('0');
}
out.append(s);
}
/**
* Prints an int as four digits into the buffer.
* Prints an BigInteger as a String.
*
* @param out
* The formatted string will be appended into this buffer.
* @param number
* Number to be printed. Must be positive.
* The integer to be printed.
* @param nDigits
* The field will be printed by using at least this
* number of digits. For example, 5 will be printed as "0005"
* if nDigits==4.
*/
private int print4Number( char[] out, int bufptr, int number ) {
out[bufptr+3] = (char) ('0'+(number%10));
number /= 10;
out[bufptr+2] = (char) ('0'+(number%10));
number /= 10;
out[bufptr+1] = (char) ('0'+(number%10));
number /= 10;
out[bufptr ] = (char) ('0'+(number%10));
return bufptr+4;
private void printNumber( StringBuilder out, BigInteger number, int nDigits) {
String s = number.toString();
for (int i=s.length(); i < nDigits; i++) {
out.append('0');
}
out.append(s);
}
/**
@ -3085,6 +3108,26 @@ public class XMLGregorianCalendarImpl
* with the creation of new <code>XMLGregorianCalendar</code>s.</p>
*/
public void reset() {
//PENDING : Implementation of reset method
eon = orig_eon;
year = orig_year;
month = orig_month;
day = orig_day;
hour = orig_hour;
minute = orig_minute;
second = orig_second;
fractionalSecond = orig_fracSeconds;
timezone = orig_timezone;
}
/** Deserialize Calendar. */
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException {
// perform default deseralization
ois.defaultReadObject();
// initialize orig_* fields
save();
} // readObject(ObjectInputStream)
}