From: jzhou Date: Fri, 4 Feb 2011 01:36:33 +0000 (+0000) Subject: Class library for SPECjbb X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=844ac2949487feff972173b6115964d04b311855;p=IRC.git Class library for SPECjbb --- diff --git a/Robust/src/ClassLibrary/MGC/Object.java b/Robust/src/ClassLibrary/MGC/Object.java new file mode 100644 index 00000000..0fd6c15e --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/Object.java @@ -0,0 +1,38 @@ +public class Object { + public int cachedCode; //first field has to be a primitive + public boolean cachedHash; + + public native int nativehashCode(); + private Object nextlockobject; + private Object prevlockobject; + + // temporary extra unused int filed to align objects for Java + //int wkhqwemnbmwnb; + + public int hashCode() { + if (!cachedHash) { + cachedCode=nativehashCode(); + cachedHash=true; + } + return cachedCode; + } + + /* DON'T USE THIS METHOD UNLESS NECESSARY */ + /* WE WILL DEPRECATE IT AS SOON AS INSTANCEOF WORKS */ + public native int getType(); + + public native int MonitorEnter(); + public native int MonitorExit(); + + public String toString() { + return "Object"+hashCode(); + } + + public boolean equals(Object o) { + if (o==this) + return true; + return false; + } + + //public final native Class getClass(); +} diff --git a/Robust/src/ClassLibrary/MGC/Thread.java b/Robust/src/ClassLibrary/MGC/Thread.java new file mode 100644 index 00000000..50c5580f --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/Thread.java @@ -0,0 +1,27 @@ +public class Thread { + private boolean finished; + + public void start() { + nativeCreate(); + } + + private static void staticStart(Thread t) { + t.run(); + } + + public static native void yield(); + + public void join() { + nativeJoin(); + } + + private native void nativeJoin(); + + public native static void sleep(long millis); + + public void run() { + } + + private native void nativeCreate(); + +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/ArrayList.java b/Robust/src/ClassLibrary/MGC/gnu/ArrayList.java new file mode 100644 index 00000000..4d17b61f --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/ArrayList.java @@ -0,0 +1,606 @@ +/* ArrayList.java -- JDK1.2's answer to Vector; this is an array-backed + implementation of the List interface + Copyright (C) 1998, 1999, 2000, 2001, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.util; + +/*import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Array; +*/ +/** + * An array-backed implementation of the List interface. This implements + * all optional list operations, and permits null elements, so that it is + * better than Vector, which it replaces. Random access is roughly constant + * time, and iteration is roughly linear time, so it is nice and fast, with + * less overhead than a LinkedList. + *

+ * + * Each list has a capacity, and as the array reaches that capacity it + * is automatically transferred to a larger array. You also have access to + * ensureCapacity and trimToSize to control the backing array's size, avoiding + * reallocation or wasted memory. + *

+ * + * ArrayList is not synchronized, so if you need multi-threaded access, + * consider using:
+ * List l = Collections.synchronizedList(new ArrayList(...)); + *

+ * + * The iterators are fail-fast, meaning that any structural + * modification, except for remove() called on the iterator + * itself, cause the iterator to throw a + * {@link ConcurrentModificationException} rather than exhibit + * non-deterministic behavior. + * + * @author Jon A. Zeppieri + * @author Bryce McKinlay + * @author Eric Blake (ebb9@email.byu.edu) + * @see Collection + * @see List + * @see LinkedList + * @see Vector + * @see Collections#synchronizedList(List) + * @see AbstractList + * @status updated to 1.4 + */ +//public class ArrayList extends AbstractList +// implements List, RandomAccess, Cloneable, Serializable +public class ArrayList +{ + /** + * Compatible with JDK 1.2 + */ + private static final long serialVersionUID = 8683452581122892189L; + + /** + * The default capacity for new ArrayLists. + */ + private static final int DEFAULT_CAPACITY = 10; + + /** + * The number of elements in this list. + * @serial the list size + */ + private int size; + + /** + * Where the data is stored. + */ + //private transient E[] data; + private transient Object[] data; + + /** + * Construct a new ArrayList with the supplied initial capacity. + * + * @param capacity initial capacity of this ArrayList + * @throws IllegalArgumentException if capacity is negative + */ + public ArrayList(int capacity) + { + // Must explicitly check, to get correct exception. + if (capacity < 0) + throw new Error("Illegal Argument Exception")/*IllegalArgumentException()*/; + data = (Object/*E*/[]) new Object[capacity]; + } + + /** + * Construct a new ArrayList with the default capacity (16). + */ + public ArrayList() + { + this(DEFAULT_CAPACITY); + } + + /** + * Construct a new ArrayList, and initialize it with the elements + * in the supplied Collection. The initial capacity is 110% of the + * Collection's size. + * + * @param c the collection whose elements will initialize this list + * @throws NullPointerException if c is null + */ + /*public ArrayList(Collection c) + { + this((int) (c.size() * 1.1f)); + addAll(c); + }*/ + + /** + * Trims the capacity of this List to be equal to its size; + * a memory saver. + */ + public void trimToSize() + { + // Not a structural change from the perspective of iterators on this list, + // so don't update modCount. + if (size != data.length) + { + Object/*E*/[] newData = /*(ObjectE[])*/ new Object[size]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + } + + /** + * Guarantees that this list will have at least enough capacity to + * hold minCapacity elements. This implementation will grow the list to + * max(current * 2, minCapacity) if (minCapacity > current). The JCL says + * explictly that "this method increases its capacity to minCap", while + * the JDK 1.3 online docs specify that the list will grow to at least the + * size specified. + * + * @param minCapacity the minimum guaranteed capacity + */ + public void ensureCapacity(int minCapacity) + { + int current = data.length; + + if (minCapacity > current) + { + Object/*E*/[] newData = /*(E[])*/ new Object[Math.max(current * 2, minCapacity)]; + System.arraycopy(data, 0, newData, 0, size); + data = newData; + } + } + + /** + * Returns the number of elements in this list. + * + * @return the list size + */ + public int size() + { + return size; + } + + /** + * Checks if the list is empty. + * + * @return true if there are no elements + */ + public boolean isEmpty() + { + return size == 0; + } + + /** + * Returns true iff element is in this ArrayList. + * + * @param e the element whose inclusion in the List is being tested + * @return true if the list contains e + */ + public boolean contains(Object e) + { + return indexOf(e) != -1; + } + + /** + * Returns the lowest index at which element appears in this List, or + * -1 if it does not appear. + * + * @param e the element whose inclusion in the List is being tested + * @return the index where e was found + */ + public int indexOf(Object e) + { + for (int i = 0; i < size; i++) + if (equals(e, data[i])) + return i; + return -1; + } + + /** + * Returns the highest index at which element appears in this List, or + * -1 if it does not appear. + * + * @param e the element whose inclusion in the List is being tested + * @return the index where e was found + */ + public int lastIndexOf(Object e) + { + for (int i = size - 1; i >= 0; i--) + if (equals(e, data[i])) + return i; + return -1; + } + + /** + * Creates a shallow copy of this ArrayList (elements are not cloned). + * + * @return the cloned object + */ + public Object clone() + { + ArrayList/**/ clone = null; + //try + { + //clone = (ArrayList) super.clone(); + clone = new ArrayList(); + clone.data = /*(E[])*/ data.clone(); + } + /*catch (CloneNotSupportedException e) + { + // Impossible to get here. + }*/ + return clone; + } + + /** + * Returns an Object array containing all of the elements in this ArrayList. + * The array is independent of this list. + * + * @return an array representation of this list + */ + public Object[] toArray() + { + Object/*E*/[] array = /*(E[])*/ new Object[size]; + System.arraycopy(data, 0, array, 0, size); + return array; + } + + /** + * Returns an Array whose component type is the runtime component type of + * the passed-in Array. The returned Array is populated with all of the + * elements in this ArrayList. If the passed-in Array is not large enough + * to store all of the elements in this List, a new Array will be created + * and returned; if the passed-in Array is larger than the size + * of this List, then size() index will be set to null. + * + * @param a the passed-in Array + * @return an array representation of this list + * @throws ArrayStoreException if the runtime type of a does not allow + * an element in this list + * @throws NullPointerException if a is null + */ + /*public T[] toArray(T[] a) + { + if (a.length < size) + a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); + else if (a.length > size) + a[size] = null; + System.arraycopy(data, 0, a, 0, size); + return a; + }*/ + + /** + * Retrieves the element at the user-supplied index. + * + * @param index the index of the element we are fetching + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object/*E*/ get(int index) + { + checkBoundExclusive(index); + return data[index]; + } + + /** + * Sets the element at the specified index. The new element, e, + * can be an object of any type or null. + * + * @param index the index at which the element is being set + * @param e the element to be set + * @return the element previously at the specified index + * @throws IndexOutOfBoundsException if index < 0 || index >= 0 + */ + public Object/*E*/ set(int index, Object/*E*/ e) + { + checkBoundExclusive(index); + Object/*E*/ result = data[index]; + data[index] = e; + return result; + } + + /** + * Appends the supplied element to the end of this list. + * The element, e, can be an object of any type or null. + * + * @param e the element to be appended to this list + * @return true, the add will always succeed + */ + public boolean add(Object/*E*/ e) + { + modCount++; + if (size == data.length) + ensureCapacity(size + 1); + data[size++] = e; + return true; + } + + /** + * Adds the supplied element at the specified index, shifting all + * elements currently at that index or higher one to the right. + * The element, e, can be an object of any type or null. + * + * @param index the index at which the element is being added + * @param e the item being added + * @throws IndexOutOfBoundsException if index < 0 || index > size() + */ + public void add(int index, Object/*E*/ e) + { + checkBoundInclusive(index); + modCount++; + if (size == data.length) + ensureCapacity(size + 1); + if (index != size) + System.arraycopy(data, index, data, index + 1, size - index); + data[index] = e; + size++; + } + + /** + * Removes the element at the user-supplied index. + * + * @param index the index of the element to be removed + * @return the removed Object + * @throws IndexOutOfBoundsException if index < 0 || index >= size() + */ + public Object/*E*/ remove(int index) + { + checkBoundExclusive(index); + Object/*E*/ r = data[index]; + modCount++; + if (index != --size) + System.arraycopy(data, index + 1, data, index, size - index); + // Aid for garbage collection by releasing this pointer. + data[size] = null; + return r; + } + + /** + * Removes all elements from this List + */ + public void clear() + { + if (size > 0) + { + modCount++; + // Allow for garbage collection. + Arrays.fill(data, 0, size, null); + size = 0; + } + } + + /** + * Add each element in the supplied Collection to this List. It is undefined + * what happens if you modify the list while this is taking place; for + * example, if the collection contains this list. c can contain objects + * of any type, as well as null values. + * + * @param c a Collection containing elements to be added to this List + * @return true if the list was modified, in other words c is not empty + * @throws NullPointerException if c is null + */ + /*public boolean addAll(Collection c) + { + return addAll(size, c); + }*/ + + /** + * Add all elements in the supplied collection, inserting them beginning + * at the specified index. c can contain objects of any type, as well + * as null values. + * + * @param index the index at which the elements will be inserted + * @param c the Collection containing the elements to be inserted + * @throws IndexOutOfBoundsException if index < 0 || index > 0 + * @throws NullPointerException if c is null + */ + /*public boolean addAll(int index, Collection c) + { + checkBoundInclusive(index); + Iterator itr = c.iterator(); + int csize = c.size(); + + modCount++; + if (csize + size > data.length) + ensureCapacity(size + csize); + int end = index + csize; + if (size > 0 && index != size) + System.arraycopy(data, index, data, end, size - index); + size += csize; + for ( ; index < end; index++) + data[index] = itr.next(); + return csize > 0; + }*/ + + /** + * Removes all elements in the half-open interval [fromIndex, toIndex). + * Does nothing when toIndex is equal to fromIndex. + * + * @param fromIndex the first index which will be removed + * @param toIndex one greater than the last index which will be removed + * @throws IndexOutOfBoundsException if fromIndex > toIndex + */ + protected void removeRange(int fromIndex, int toIndex) + { + int change = toIndex - fromIndex; + if (change > 0) + { + modCount++; + System.arraycopy(data, toIndex, data, fromIndex, size - toIndex); + size -= change; + } + else if (change < 0) + throw new Error("Index Out Of Bounds Exception")/*IndexOutOfBoundsException()*/; + } + + /** + * Checks that the index is in the range of possible elements (inclusive). + * + * @param index the index to check + * @throws IndexOutOfBoundsException if index > size + */ + private void checkBoundInclusive(int index) + { + // Implementation note: we do not check for negative ranges here, since + // use of a negative index will cause an ArrayIndexOutOfBoundsException, + // a subclass of the required exception, with no effort on our part. + if (index > size) + raiseBoundsError(index); + } + + /** + * Checks that the index is in the range of existing elements (exclusive). + * + * @param index the index to check + * @throws IndexOutOfBoundsException if index >= size + */ + private void checkBoundExclusive(int index) + { + // Implementation note: we do not check for negative ranges here, since + // use of a negative index will cause an ArrayIndexOutOfBoundsException, + // a subclass of the required exception, with no effort on our part. + if (index >= size) + raiseBoundsError(index); + } + + /** + * Raise the ArrayIndexOfOutBoundsException. + * + * @param index the index of the access + * @throws IndexOutOfBoundsException unconditionally + */ + private void raiseBoundsError(int index) + { + // Implementaion note: put in a separate method to make the JITs job easier + // (separate common from uncommon code at method boundaries when trivial to + // do so). + throw new Error/*IndexOutOfBoundsException*/("IndexOutOfBoundsException Index: " + index + ", Size: " + size); + } + + + /** + * Remove from this list all elements contained in the given collection. + * This is not public, due to Sun's API, but this performs in linear + * time while the default behavior of AbstractList would be quadratic. + * + * @param c the collection to filter out + * @return true if this list changed + * @throws NullPointerException if c is null + */ + /*boolean removeAllInternal(Collection c) + { + int i; + int j; + for (i = 0; i < size; i++) + if (c.contains(data[i])) + break; + if (i == size) + return false; + + modCount++; + for (j = i++; i < size; i++) + if (! c.contains(data[i])) + data[j++] = data[i]; + size -= i - j; + return true; + }*/ + + /** + * Retain in this vector only the elements contained in the given collection. + * This is not public, due to Sun's API, but this performs in linear + * time while the default behavior of AbstractList would be quadratic. + * + * @param c the collection to filter by + * @return true if this vector changed + * @throws NullPointerException if c is null + * @since 1.2 + */ + /*boolean retainAllInternal(Collection c) + { + int i; + int j; + for (i = 0; i < size; i++) + if (! c.contains(data[i])) + break; + if (i == size) + return false; + + modCount++; + for (j = i++; i < size; i++) + if (c.contains(data[i])) + data[j++] = data[i]; + size -= i - j; + return true; + }*/ + + /** + * Serializes this object to the given stream. + * + * @param s the stream to write to + * @throws IOException if the underlying stream fails + * @serialData the size field (int), the length of the backing array + * (int), followed by its elements (Objects) in proper order. + */ + /*private void writeObject(ObjectOutputStream s) throws IOException + { + // The 'size' field. + s.defaultWriteObject(); + // We serialize unused list entries to preserve capacity. + int len = data.length; + s.writeInt(len); + // it would be more efficient to just write "size" items, + // this need readObject read "size" items too. + for (int i = 0; i < size; i++) + s.writeObject(data[i]); + }*/ + + /** + * Deserializes this object from the given stream. + * + * @param s the stream to read from + * @throws ClassNotFoundException if the underlying stream fails + * @throws IOException if the underlying stream fails + * @serialData the size field (int), the length of the backing array + * (int), followed by its elements (Objects) in proper order. + */ + /*private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + // the `size' field. + s.defaultReadObject(); + int capacity = s.readInt(); + data = (E[]) new Object[capacity]; + for (int i = 0; i < size; i++) + data[i] = (E) s.readObject(); + }*/ +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/BigDecimal.java b/Robust/src/ClassLibrary/MGC/gnu/BigDecimal.java new file mode 100644 index 00000000..bc265e8d --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/BigDecimal.java @@ -0,0 +1,1559 @@ +/* java.math.BigDecimal -- Arbitrary precision decimals. + Copyright (C) 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.math; + +//import gnu.java.lang.CPStringBuilder; + +public class BigDecimal //extends Number implements Comparable +{ + private BigInteger intVal; + private int scale; + private int precision = 0; + private static final long serialVersionUID = 6108874887143696463L; + + /** + * The constant zero as a BigDecimal with scale zero. + * @since 1.5 + */ + public static final BigDecimal ZERO = + new BigDecimal (BigInteger.ZERO, 0); + + /** + * The constant one as a BigDecimal with scale zero. + * @since 1.5 + */ + public static final BigDecimal ONE = + new BigDecimal (BigInteger.ONE, 0); + + /** + * The constant ten as a BigDecimal with scale zero. + * @since 1.5 + */ + public static final BigDecimal TEN = + new BigDecimal (BigInteger.TEN, 0); + + public static final int ROUND_UP = 0; + public static final int ROUND_DOWN = 1; + public static final int ROUND_CEILING = 2; + public static final int ROUND_FLOOR = 3; + public static final int ROUND_HALF_UP = 4; + public static final int ROUND_HALF_DOWN = 5; + public static final int ROUND_HALF_EVEN = 6; + public static final int ROUND_UNNECESSARY = 7; + + /** + * Constructs a new BigDecimal whose unscaled value is val and whose + * scale is zero. + * @param val the value of the new BigDecimal + * @since 1.5 + */ + public BigDecimal (int val) + { + this.intVal = BigInteger.valueOf(val); + this.scale = 0; + } + + /** + * Constructs a BigDecimal using the BigDecimal(int) constructor and then + * rounds according to the MathContext. + * @param val the value for the initial (unrounded) BigDecimal + * @param mc the MathContext specifying the rounding + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal (int val, MathContext mc) + { + this (val); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + }*/ + + /** + * Constructs a new BigDecimal whose unscaled value is val and whose + * scale is zero. + * @param val the value of the new BigDecimal + */ + public BigDecimal (long val) + { + this.intVal = BigInteger.valueOf(val); + this.scale = 0; + } + + /** + * Constructs a BigDecimal from the long in the same way as BigDecimal(long) + * and then rounds according to the MathContext. + * @param val the long from which we create the initial BigDecimal + * @param mc the MathContext that specifies the rounding behaviour + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal (long val, MathContext mc) + { + this(val); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + }*/ + + /** + * Constructs a BigDecimal whose value is given by num rounded according to + * mc. Since num is already a BigInteger, the rounding refers only to the + * precision setting in mc, if mc.getPrecision() returns an int lower than + * the number of digits in num, then rounding is necessary. + * @param num the unscaledValue, before rounding + * @param mc the MathContext that specifies the precision + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * * @since 1.5 + */ + /*public BigDecimal (BigInteger num, MathContext mc) + { + this (num, 0); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + }*/ + + /** + * Constructs a BigDecimal from the String val according to the same + * rules as the BigDecimal(String) constructor and then rounds + * according to the MathContext mc. + * @param val the String from which we construct the initial BigDecimal + * @param mc the MathContext that specifies the rounding + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal (String val, MathContext mc) + { + this (val); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + }*/ + + /** + * Constructs a BigDecimal whose unscaled value is num and whose + * scale is zero. + * @param num the value of the new BigDecimal + */ + public BigDecimal (BigInteger num) + { + this (num, 0); + } + + /** + * Constructs a BigDecimal whose unscaled value is num and whose + * scale is scale. + * @param num + * @param scale + */ + public BigDecimal (BigInteger num, int scale) + { + this.intVal = num; + this.scale = scale; + } + + /** + * Constructs a BigDecimal using the BigDecimal(BigInteger, int) + * constructor and then rounds according to the MathContext. + * @param num the unscaled value of the unrounded BigDecimal + * @param scale the scale of the unrounded BigDecimal + * @param mc the MathContext specifying the rounding + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal (BigInteger num, int scale, MathContext mc) + { + this (num, scale); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + }*/ + + /** + * Constructs a BigDecimal in the same way as BigDecimal(double) and then + * rounds according to the MathContext. + * @param num the double from which the initial BigDecimal is created + * @param mc the MathContext that specifies the rounding behaviour + * @throws ArithmeticException if the result is inexact but the rounding type + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal (double num, MathContext mc) + { + this (num); + if (mc.getPrecision() != 0) + { + BigDecimal result = this.round(mc); + this.intVal = result.intVal; + this.scale = result.scale; + this.precision = result.precision; + } + }*/ + + public BigDecimal (double num) //throws NumberFormatException + { + if (Double.isInfinite (num) || Double.isNaN (num)) + throw new Error/*NumberFormatException */("invalid argument: " + num); + // Note we can't convert NUM to a String and then use the + // String-based constructor. The BigDecimal documentation makes + // it clear that the two constructors work differently. + + final int mantissaBits = 52; + final int exponentBits = 11; + final long mantMask = (1L << mantissaBits) - 1; + final long expMask = (1L << exponentBits) - 1; + + long bits = Double.doubleToLongBits (num); + long mantissa = bits & mantMask; + long exponent = (bits >>> mantissaBits) & expMask; + boolean denormal = exponent == 0; + + // Correct the exponent for the bias. + exponent -= denormal ? 1022 : 1023; + + // Now correct the exponent to account for the bits to the right + // of the decimal. + exponent -= mantissaBits; + // Ordinary numbers have an implied leading `1' bit. + if (! denormal) + mantissa |= (1L << mantissaBits); + + // Shave off factors of 10. + while (exponent < 0 && (mantissa & 1) == 0) + { + ++exponent; + mantissa >>= 1; + } + + intVal = BigInteger.valueOf (bits < 0 ? - mantissa : mantissa); + if (exponent < 0) + { + // We have MANTISSA * 2 ^ (EXPONENT). + // Since (1/2)^N == 5^N * 10^-N we can easily convert this + // into a power of 10. + scale = (int) (- exponent); + BigInteger mult = BigInteger.valueOf (5).pow (scale); + intVal = intVal.multiply (mult); + } + else + { + intVal = intVal.shiftLeft ((int) exponent); + scale = 0; + } + } + + /** + * Constructs a BigDecimal from the char subarray and rounding + * according to the MathContext. + * @param in the char array + * @param offset the start of the subarray + * @param len the length of the subarray + * @param mc the MathContext for rounding + * @throws NumberFormatException if the char subarray is not a valid + * BigDecimal representation + * @throws ArithmeticException if the result is inexact but the rounding + * mode is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal(char[] in, int offset, int len, MathContext mc) + { + this(in, offset, len); + // If mc has precision other than zero then we must round. + if (mc.getPrecision() != 0) + { + BigDecimal temp = this.round(mc); + this.intVal = temp.intVal; + this.scale = temp.scale; + this.precision = temp.precision; + } + }*/ + + /** + * Constructs a BigDecimal from the char array and rounding according + * to the MathContext. + * @param in the char array + * @param mc the MathContext + * @throws NumberFormatException if in is not a valid BigDecimal + * representation + * @throws ArithmeticException if the result is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal(char[] in, MathContext mc) + { + this(in, 0, in.length); + // If mc has precision other than zero then we must round. + if (mc.getPrecision() != 0) + { + BigDecimal temp = this.round(mc); + this.intVal = temp.intVal; + this.scale = temp.scale; + this.precision = temp.precision; + } + }*/ + + /** + * Constructs a BigDecimal from the given char array, accepting the same + * sequence of characters as the BigDecimal(String) constructor. + * @param in the char array + * @throws NumberFormatException if in is not a valid BigDecimal + * representation + * @since 1.5 + */ + public BigDecimal(char[] in) + { + this(in, 0, in.length); + } + + /** + * Constructs a BigDecimal from a char subarray, accepting the same sequence + * of characters as the BigDecimal(String) constructor. + * @param in the char array + * @param offset the start of the subarray + * @param len the length of the subarray + * @throws NumberFormatException if in is not a valid + * BigDecimal representation. + * @since 1.5 + */ + public BigDecimal(char[] in, int offset, int len) + { + // start is the index into the char array where the significand starts + int start = offset; + // end is one greater than the index of the last character used + int end = offset + len; + // point is the index into the char array where the exponent starts + // (or, if there is no exponent, this is equal to end) + int point = offset; + // dot is the index into the char array where the decimal point is + // found, or -1 if there is no decimal point + int dot = -1; + + // The following examples show what these variables mean. Note that + // point and dot don't yet have the correct values, they will be + // properly assigned in a loop later on in this method. + // + // Example 1 + // + // + 1 0 2 . 4 6 9 + // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + // + // offset = 2, len = 8, start = 3, dot = 6, point = end = 10 + // + // Example 2 + // + // + 2 3 4 . 6 1 3 E - 1 + // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + // + // offset = 2, len = 11, start = 3, dot = 6, point = 10, end = 13 + // + // Example 3 + // + // - 1 2 3 4 5 e 7 + // __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ + // + // offset = 2, len = 8, start = 3, dot = -1, point = 8, end = 10 + + // Determine the sign of the number. + boolean negative = false; + if (in[offset] == '+') + { + ++start; + ++point; + } + else if (in[offset] == '-') + { + ++start; + ++point; + negative = true; + } + + // Check each character looking for the decimal point and the + // start of the exponent. + while (point < end) + { + char c = in[point]; + if (c == '.') + { + // If dot != -1 then we've seen more than one decimal point. + if (dot != -1) + throw new Error/*NumberFormatException*/("multiple `.'s in number"); + dot = point; + } + // Break when we reach the start of the exponent. + else if (c == 'e' || c == 'E') + break; + // Throw an exception if the character was not a decimal or an + // exponent and is not a digit. + else if (!Character.isDigit(c)) + throw new Error/*NumberFormatException*/("unrecognized character at " + point + + ": " + c); + ++point; + } + + // val is a StringBuilder from which we'll create a BigInteger + // which will be the unscaled value for this BigDecimal + CPStringBuilder val = new CPStringBuilder(point - start - 1); + if (dot != -1) + { + // If there was a decimal we must combine the two parts that + // contain only digits and we must set the scale properly. + val.append(in, start, dot - start); + val.append(in, dot + 1, point - dot - 1); + scale = point - 1 - dot; + } + else + { + // If there was no decimal then the unscaled value is just the number + // formed from all the digits and the scale is zero. + val.append(in, start, point - start); + scale = 0; + } + if (val.length() == 0) + throw new Error/*NumberFormatException*/("no digits seen"); + + // Prepend a negative sign if necessary. + if (negative) + val.insert(0, '-'); + intVal = new BigInteger(val.toString()); + + // Now parse exponent. + // If point < end that means we broke out of the previous loop when we + // saw an 'e' or an 'E'. + if (point < end) + { + point++; + // Ignore a '+' sign. + if (in[point] == '+') + point++; + + // Throw an exception if there were no digits found after the 'e' + // or 'E'. + if (point >= end) + throw new Error/*NumberFormatException*/("no exponent following e or E"); + + try + { + // Adjust the scale according to the exponent. + // Remember that the value of a BigDecimal is + // unscaledValue x Math.pow(10, -scale) + scale -= Integer.parseInt(new String(in, point, end - point)); + } + catch (Error/*NumberFormatException*/ ex) + { + throw new Error/*NumberFormatException*/("malformed exponent"); + } + } + } + + public BigDecimal (String num) //throws NumberFormatException + { + int len = num.length(); + int start = 0, point = 0; + int dot = -1; + boolean negative = false; + if (num.charAt(0) == '+') + { + ++start; + ++point; + } + else if (num.charAt(0) == '-') + { + ++start; + ++point; + negative = true; + } + + while (point < len) + { + char c = num.charAt (point); + if (c == '.') + { + if (dot >= 0) + throw new Error/*NumberFormatException*/ ("multiple `.'s in number"); + dot = point; + } + else if (c == 'e' || c == 'E') + break; + else if (Character.digit (c, 10) < 0) + throw new Error/*NumberFormatException*/ ("unrecognized character: " + c); + ++point; + } + + String val; + if (dot >= 0) + { + val = num.substring (start, dot) + num.substring (dot + 1, point); + scale = point - 1 - dot; + } + else + { + val = num.substring (start, point); + scale = 0; + } + if (val.length () == 0) + throw new Error/*NumberFormatException*/ ("no digits seen"); + + if (negative) + val = "-" + val; + intVal = new BigInteger (val); + + // Now parse exponent. + if (point < len) + { + point++; + if (num.charAt(point) == '+') + point++; + + if (point >= len ) + throw new Error/*NumberFormatException*/ ("no exponent following e or E"); + + try + { + scale -= Integer.parseInt (num.substring (point)); + } + catch (Error/*NumberFormatException*/ ex) + { + throw new Error/*NumberFormatException*/ ("malformed exponent"); + } + } + } + + public static BigDecimal valueOf (long val) + { + return valueOf (val, 0); + } + + public static BigDecimal valueOf (long val, int scale) + //throws NumberFormatException + { + if ((scale == 0) && ((int)val == val)) + switch ((int) val) + { + case 0: + return ZERO; + case 1: + return ONE; + } + + return new BigDecimal (BigInteger.valueOf (val), scale); + } + + public BigDecimal add (BigDecimal val) + { + // For addition, need to line up decimals. Note that the movePointRight + // method cannot be used for this as it might return a BigDecimal with + // scale == 0 instead of the scale we need. + BigInteger op1 = intVal; + BigInteger op2 = val.intVal; + if (scale < val.scale) + op1 = op1.multiply (BigInteger.TEN.pow (val.scale - scale)); + else if (scale > val.scale) + op2 = op2.multiply (BigInteger.TEN.pow (scale - val.scale)); + + return new BigDecimal (op1.add (op2), Math.max (scale, val.scale)); + } + + /** + * Returns a BigDecimal whose value is found first by calling the + * method add(val) and then by rounding according to the MathContext mc. + * @param val the augend + * @param mc the MathContext for rounding + * @throws ArithmeticException if the value is inexact but the rounding is + * RoundingMode.UNNECESSARY + * @return this + val, rounded if need be + * @since 1.5 + */ + /*public BigDecimal add (BigDecimal val, MathContext mc) + { + return add(val).round(mc); + }*/ + + public BigDecimal subtract (BigDecimal val) + { + return this.add(val.negate()); + } + + /** + * Returns a BigDecimal whose value is found first by calling the + * method subtract(val) and then by rounding according to the MathContext mc. + * @param val the subtrahend + * @param mc the MathContext for rounding + * @throws ArithmeticException if the value is inexact but the rounding is + * RoundingMode.UNNECESSARY + * @return this - val, rounded if need be + * @since 1.5 + */ + /*public BigDecimal subtract (BigDecimal val, MathContext mc) + { + return subtract(val).round(mc); + }*/ + + public BigDecimal multiply (BigDecimal val) + { + return new BigDecimal (intVal.multiply (val.intVal), scale + val.scale); + } + + /** + * Returns a BigDecimal whose value is (this x val) before it is rounded + * according to the MathContext mc. + * @param val the multiplicand + * @param mc the MathContext for rounding + * @return a new BigDecimal with value approximately (this x val) + * @throws ArithmeticException if the value is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal multiply (BigDecimal val, MathContext mc) + { + return multiply(val).round(mc); + }*/ + + public BigDecimal divide (BigDecimal val, int roundingMode) + //throws ArithmeticException, IllegalArgumentException + { + return divide (val, scale, roundingMode); + } + + /** + * Returns a BigDecimal whose value is (this / val), with the specified scale + * and rounding according to the RoundingMode + * @param val the divisor + * @param scale the scale of the BigDecimal returned + * @param roundingMode the rounding mode to use + * @return a BigDecimal whose value is approximately (this / val) + * @throws ArithmeticException if divisor is zero or the rounding mode is + * UNNECESSARY but the specified scale cannot represent the value exactly + * @since 1.5 + */ + /*public BigDecimal divide(BigDecimal val, + int scale, RoundingMode roundingMode) + { + return divide (val, scale, roundingMode.ordinal()); + }*/ + + /** + * Returns a BigDecimal whose value is (this / val) rounded according to the + * RoundingMode + * @param val the divisor + * @param roundingMode the rounding mode to use + * @return a BigDecimal whose value is approximately (this / val) + * @throws ArithmeticException if divisor is zero or the rounding mode is + * UNNECESSARY but the specified scale cannot represent the value exactly + */ + /*public BigDecimal divide (BigDecimal val, RoundingMode roundingMode) + { + return divide (val, scale, roundingMode.ordinal()); + }*/ + + public BigDecimal divide(BigDecimal val, int newScale, int roundingMode) + //throws ArithmeticException, IllegalArgumentException + { + if (roundingMode < 0 || roundingMode > 7) + throw + new Error/*IllegalArgumentException*/("illegal rounding mode: " + roundingMode); + + if (intVal.signum () == 0) // handle special case of 0.0/0.0 + return newScale == 0 ? ZERO : new BigDecimal (ZERO.intVal, newScale); + + // Ensure that pow gets a non-negative value. + BigInteger valIntVal = val.intVal; + int power = newScale - (scale - val.scale); + if (power < 0) + { + // Effectively increase the scale of val to avoid an + // ArithmeticException for a negative power. + valIntVal = valIntVal.multiply (BigInteger.TEN.pow (-power)); + power = 0; + } + + BigInteger dividend = intVal.multiply (BigInteger.TEN.pow (power)); + + BigInteger parts[] = dividend.divideAndRemainder (valIntVal); + + BigInteger unrounded = parts[0]; + if (parts[1].signum () == 0) // no remainder, no rounding necessary + return new BigDecimal (unrounded, newScale); + + if (roundingMode == ROUND_UNNECESSARY) + throw new Error/*ArithmeticException*/ ("Rounding necessary"); + + int sign = intVal.signum () * valIntVal.signum (); + + if (roundingMode == ROUND_CEILING) + roundingMode = (sign > 0) ? ROUND_UP : ROUND_DOWN; + else if (roundingMode == ROUND_FLOOR) + roundingMode = (sign < 0) ? ROUND_UP : ROUND_DOWN; + else + { + // half is -1 if remainder*2 < positive intValue (*power), 0 if equal, + // 1 if >. This implies that the remainder to round is less than, + // equal to, or greater than half way to the next digit. + BigInteger posRemainder + = parts[1].signum () < 0 ? parts[1].negate() : parts[1]; + valIntVal = valIntVal.signum () < 0 ? valIntVal.negate () : valIntVal; + int half = posRemainder.shiftLeft(1).compareTo(valIntVal); + + switch(roundingMode) + { + case ROUND_HALF_UP: + roundingMode = (half < 0) ? ROUND_DOWN : ROUND_UP; + break; + case ROUND_HALF_DOWN: + roundingMode = (half > 0) ? ROUND_UP : ROUND_DOWN; + break; + case ROUND_HALF_EVEN: + if (half < 0) + roundingMode = ROUND_DOWN; + else if (half > 0) + roundingMode = ROUND_UP; + else if (unrounded.testBit(0)) // odd, then ROUND_HALF_UP + roundingMode = ROUND_UP; + else // even, ROUND_HALF_DOWN + roundingMode = ROUND_DOWN; + break; + } + } + + if (roundingMode == ROUND_UP) + unrounded = unrounded.add (BigInteger.valueOf (sign > 0 ? 1 : -1)); + + // roundingMode == ROUND_DOWN + return new BigDecimal (unrounded, newScale); + } + + /** + * Performs division, if the resulting quotient requires rounding + * (has a nonterminating decimal expansion), + * an ArithmeticException is thrown. + * #see divide(BigDecimal, int, int) + * @since 1.5 + */ + public BigDecimal divide(BigDecimal divisor) + //throws ArithmeticException, IllegalArgumentException + { + return divide(divisor, scale, ROUND_UNNECESSARY); + } + + /** + * Returns a BigDecimal whose value is the remainder in the quotient + * this / val. This is obtained by + * subtract(divideToIntegralValue(val).multiply(val)). + * @param val the divisor + * @return a BigDecimal whose value is the remainder + * @throws ArithmeticException if val == 0 + * @since 1.5 + */ + public BigDecimal remainder(BigDecimal val) + { + return subtract(divideToIntegralValue(val).multiply(val)); + } + + /** + * Returns a BigDecimal array, the first element of which is the integer part + * of this / val, and the second element of which is the remainder of + * that quotient. + * @param val the divisor + * @return the above described BigDecimal array + * @throws ArithmeticException if val == 0 + * @since 1.5 + */ + public BigDecimal[] divideAndRemainder(BigDecimal val) + { + BigDecimal[] result = new BigDecimal[2]; + result[0] = divideToIntegralValue(val); + result[1] = subtract(result[0].multiply(val)); + return result; + } + + /** + * Returns a BigDecimal whose value is the integer part of the quotient + * this / val. The preferred scale is this.scale - val.scale. + * @param val the divisor + * @return a BigDecimal whose value is the integer part of this / val. + * @throws ArithmeticException if val == 0 + * @since 1.5 + */ + public BigDecimal divideToIntegralValue(BigDecimal val) + { + return divide(val, ROUND_DOWN).floor().setScale(scale - val.scale, ROUND_DOWN); + } + + /** + * Mutates this BigDecimal into one with no fractional part, whose value is + * equal to the largest integer that is <= to this BigDecimal. Note that + * since this method is private it is okay to mutate this BigDecimal. + * @return the BigDecimal obtained through the floor operation on this + * BigDecimal. + */ + private BigDecimal floor() + { + if (scale <= 0) + return this; + String intValStr = intVal.toString(); + intValStr = intValStr.substring(0, intValStr.length() - scale); + intVal = new BigInteger(intValStr).multiply(BigInteger.TEN.pow(scale)); + return this; + } + + public int compareTo (BigDecimal val) + { + if (scale == val.scale) + return intVal.compareTo (val.intVal); + + BigInteger thisParts[] = + intVal.divideAndRemainder (BigInteger.TEN.pow (scale)); + BigInteger valParts[] = + val.intVal.divideAndRemainder (BigInteger.TEN.pow (val.scale)); + + int compare; + if ((compare = thisParts[0].compareTo (valParts[0])) != 0) + return compare; + + // quotients are the same, so compare remainders + + // Add some trailing zeros to the remainder with the smallest scale + if (scale < val.scale) + thisParts[1] = thisParts[1].multiply + (BigInteger.valueOf (10).pow (val.scale - scale)); + else if (scale > val.scale) + valParts[1] = valParts[1].multiply + (BigInteger.valueOf (10).pow (scale - val.scale)); + + // and compare them + return thisParts[1].compareTo (valParts[1]); + } + + public boolean equals (Object o) + { + return (o instanceof BigDecimal + && scale == ((BigDecimal) o).scale + && compareTo ((BigDecimal) o) == 0); + } + + public int hashCode() + { + return intValue() ^ scale; + } + + public BigDecimal max (BigDecimal val) + { + switch (compareTo (val)) + { + case 1: + return this; + default: + return val; + } + } + + public BigDecimal min (BigDecimal val) + { + switch (compareTo (val)) + { + case -1: + return this; + default: + return val; + } + } + + public BigDecimal movePointLeft (int n) + { + return (n < 0) ? movePointRight (-n) : new BigDecimal (intVal, scale + n); + } + + public BigDecimal movePointRight (int n) + { + if (n < 0) + return movePointLeft (-n); + + if (scale >= n) + return new BigDecimal (intVal, scale - n); + + return new BigDecimal (intVal.multiply + (BigInteger.TEN.pow (n - scale)), 0); + } + + public int signum () + { + return intVal.signum (); + } + + public int scale () + { + return scale; + } + + public BigInteger unscaledValue() + { + return intVal; + } + + public BigDecimal abs () + { + return new BigDecimal (intVal.abs (), scale); + } + + public BigDecimal negate () + { + return new BigDecimal (intVal.negate (), scale); + } + + /** + * Returns a BigDecimal whose value is found first by negating this via + * the negate() method, then by rounding according to the MathContext mc. + * @param mc the MathContext for rounding + * @return a BigDecimal whose value is approximately (-this) + * @throws ArithmeticException if the value is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal negate(MathContext mc) + { + BigDecimal result = negate(); + if (mc.getPrecision() != 0) + result = result.round(mc); + return result; + }*/ + + /** + * Returns this BigDecimal. This is included for symmetry with the + * method negate(). + * @return this + * @since 1.5 + */ + public BigDecimal plus() + { + return this; + } + + /** + * Returns a BigDecimal whose value is found by rounding this + * according to the MathContext. This is the same as round(MathContext). + * @param mc the MathContext for rounding + * @return a BigDecimal whose value is this before being rounded + * @throws ArithmeticException if the value is inexact but the rounding mode + * is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal plus(MathContext mc) + { + return round(mc); + }*/ + + /** + * Returns a BigDecimal which is this BigDecimal rounded according to the + * MathContext rounding settings. + * @param mc the MathContext that tells us how to round + * @return the rounded BigDecimal + */ + /*public BigDecimal round(MathContext mc) + { + int mcPrecision = mc.getPrecision(); + int numToChop = precision() - mcPrecision; + // If mc specifies not to chop any digits or if we've already chopped + // enough digits (say by using a MathContext in the constructor for this + // BigDecimal) then just return this. + if (mcPrecision == 0 || numToChop <= 0) + return this; + + // Make a new BigDecimal which is the correct power of 10 to chop off + // the required number of digits and then call divide. + BigDecimal div = new BigDecimal(BigInteger.TEN.pow(numToChop)); + BigDecimal rounded = divide(div, scale, mc.getRoundingMode().ordinal()); + rounded.scale -= numToChop; + rounded.precision = mcPrecision; + return rounded; + }*/ + + /** + * Returns the precision of this BigDecimal (the number of digits in the + * unscaled value). The precision of a zero value is 1. + * @return the number of digits in the unscaled value, or 1 if the value + * is zero. + */ + public int precision() + { + if (precision == 0) + { + String s = intVal.toString(); + precision = s.length() - (( s.charAt(0) == '-' ) ? 1 : 0); + } + return precision; + } + + /** + * Returns the String representation of this BigDecimal, using scientific + * notation if necessary. The following steps are taken to generate + * the result: + * + * 1. the BigInteger unscaledValue's toString method is called and if + * scale == 0 is returned. + * 2. an int adjExp is created which is equal to the negation + * of scale plus the number of digits in the unscaled value, + * minus one. + * 3. if scale >= 0 && adjExp >= -6 then we represent this + * BigDecimal without scientific notation. A decimal is added if the + * scale is positive and zeros are prepended as necessary. + * 4. if scale is negative or adjExp is less than -6 we use scientific + * notation. If the unscaled value has more than one digit, a decimal + * as inserted after the first digit, the character 'E' is appended + * and adjExp is appended. + */ + /*public String toString() + { + // bigStr is the String representation of the unscaled value. If + // scale is zero we simply return this. + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + boolean negative = (bigStr.charAt(0) == '-'); + int point = bigStr.length() - scale - (negative ? 1 : 0); + + CPStringBuilder val = new CPStringBuilder(); + + if (scale >= 0 && (point - 1) >= -6) + { + // Convert to character form without scientific notation. + if (point <= 0) + { + // Zeros need to be prepended to the StringBuilder. + if (negative) + val.append('-'); + // Prepend a '0' and a '.' and then as many more '0's as necessary. + val.append('0').append('.'); + while (point < 0) + { + val.append('0'); + point++; + } + // Append the unscaled value. + val.append(bigStr.substring(negative ? 1 : 0)); + } + else + { + // No zeros need to be prepended so the String is simply the + // unscaled value with the decimal point inserted. + val.append(bigStr); + val.insert(point + (negative ? 1 : 0), '.'); + } + } + else + { + // We must use scientific notation to represent this BigDecimal. + val.append(bigStr); + // If there is more than one digit in the unscaled value we put a + // decimal after the first digit. + if (bigStr.length() > 1) + val.insert( ( negative ? 2 : 1 ), '.'); + // And then append 'E' and the exponent = (point - 1). + val.append('E'); + if (point - 1 >= 0) + val.append('+'); + val.append( point - 1 ); + } + return val.toString(); + }*/ + + /** + * Returns the String representation of this BigDecimal, using engineering + * notation if necessary. This is similar to toString() but when exponents + * are used the exponent is made to be a multiple of 3 such that the integer + * part is between 1 and 999. + * + * @return a String representation of this BigDecimal in engineering notation + * @since 1.5 + */ + /*public String toEngineeringString() + { + // bigStr is the String representation of the unscaled value. If + // scale is zero we simply return this. + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + boolean negative = (bigStr.charAt(0) == '-'); + int point = bigStr.length() - scale - (negative ? 1 : 0); + + // This is the adjusted exponent described above. + int adjExp = point - 1; + CPStringBuilder val = new CPStringBuilder(); + + if (scale >= 0 && adjExp >= -6) + { + // Convert to character form without scientific notation. + if (point <= 0) + { + // Zeros need to be prepended to the StringBuilder. + if (negative) + val.append('-'); + // Prepend a '0' and a '.' and then as many more '0's as necessary. + val.append('0').append('.'); + while (point < 0) + { + val.append('0'); + point++; + } + // Append the unscaled value. + val.append(bigStr.substring(negative ? 1 : 0)); + } + else + { + // No zeros need to be prepended so the String is simply the + // unscaled value with the decimal point inserted. + val.append(bigStr); + val.insert(point + (negative ? 1 : 0), '.'); + } + } + else + { + // We must use scientific notation to represent this BigDecimal. + // The exponent must be a multiple of 3 and the integer part + // must be between 1 and 999. + val.append(bigStr); + int zeros = adjExp % 3; + int dot = 1; + if (adjExp > 0) + { + // If the exponent is positive we just move the decimal to the + // right and decrease the exponent until it is a multiple of 3. + dot += zeros; + adjExp -= zeros; + } + else + { + // If the exponent is negative then we move the dot to the right + // and decrease the exponent (increase its magnitude) until + // it is a multiple of 3. Note that this is not adjExp -= zeros + // because the mod operator doesn't give us the distance to the + // correct multiple of 3. (-5 mod 3) is -2 but the distance from + // -5 to the correct multiple of 3 (-6) is 1, not 2. + if (zeros == -2) + { + dot += 1; + adjExp -= 1; + } + else if (zeros == -1) + { + dot += 2; + adjExp -= 2; + } + } + + // Either we have to append zeros because, for example, 1.1E+5 should + // be 110E+3, or we just have to put the decimal in the right place. + if (dot > val.length()) + { + while (dot > val.length()) + val.append('0'); + } + else if (bigStr.length() > dot) + val.insert(dot + (negative ? 1 : 0), '.'); + + // And then append 'E' and the exponent (adjExp). + val.append('E'); + if (adjExp >= 0) + val.append('+'); + val.append(adjExp); + } + return val.toString(); + }*/ + + /** + * Returns a String representation of this BigDecimal without using + * scientific notation. This is how toString() worked for releases 1.4 + * and previous. Zeros may be added to the end of the String. For + * example, an unscaled value of 1234 and a scale of -3 would result in + * the String 1234000, but the toString() method would return + * 1.234E+6. + * @return a String representation of this BigDecimal + * @since 1.5 + */ + /*public String toPlainString() + { + // If the scale is zero we simply return the String representation of the + // unscaled value. + String bigStr = intVal.toString(); + if (scale == 0) + return bigStr; + + // Remember if we have to put a negative sign at the start. + boolean negative = (bigStr.charAt(0) == '-'); + + int point = bigStr.length() - scale - (negative ? 1 : 0); + + CPStringBuilder sb = new CPStringBuilder(bigStr.length() + 2 + + (point <= 0 ? (-point + 1) : 0)); + if (point <= 0) + { + // We have to prepend zeros and a decimal point. + if (negative) + sb.append('-'); + sb.append('0').append('.'); + while (point < 0) + { + sb.append('0'); + point++; + } + sb.append(bigStr.substring(negative ? 1 : 0)); + } + else if (point < bigStr.length()) + { + // No zeros need to be prepended or appended, just put the decimal + // in the right place. + sb.append(bigStr); + sb.insert(point + (negative ? 1 : 0), '.'); + } + else + { + // We must append zeros instead of using scientific notation. + sb.append(bigStr); + for (int i = bigStr.length(); i < point; i++) + sb.append('0'); + } + return sb.toString(); + }*/ + + /** + * Converts this BigDecimal to a BigInteger. Any fractional part will + * be discarded. + * @return a BigDecimal whose value is equal to floor[this] + */ + public BigInteger toBigInteger () + { + // If scale > 0 then we must divide, if scale > 0 then we must multiply, + // and if scale is zero then we just return intVal; + if (scale > 0) + return intVal.divide (BigInteger.TEN.pow (scale)); + else if (scale < 0) + return intVal.multiply(BigInteger.TEN.pow(-scale)); + return intVal; + } + + /** + * Converts this BigDecimal into a BigInteger, throwing an + * ArithmeticException if the conversion is not exact. + * @return a BigInteger whose value is equal to the value of this BigDecimal + * @since 1.5 + */ + public BigInteger toBigIntegerExact() + { + if (scale > 0) + { + // If we have to divide, we must check if the result is exact. + BigInteger[] result = + intVal.divideAndRemainder(BigInteger.TEN.pow(scale)); + if (result[1].equals(BigInteger.ZERO)) + return result[0]; + throw new Error/*ArithmeticException*/("No exact BigInteger representation"); + } + else if (scale < 0) + // If we're multiplying instead, then we needn't check for exactness. + return intVal.multiply(BigInteger.TEN.pow(-scale)); + // If the scale is zero we can simply return intVal. + return intVal; + } + + public int intValue () + { + return toBigInteger ().intValue (); + } + + /** + * Returns a BigDecimal which is numerically equal to this BigDecimal but + * with no trailing zeros in the representation. For example, if this + * BigDecimal has [unscaledValue, scale] = [6313000, 4] this method returns + * a BigDecimal with [unscaledValue, scale] = [6313, 1]. As another + * example, [12400, -2] would become [124, -4]. + * @return a numerically equal BigDecimal with no trailing zeros + */ + public BigDecimal stripTrailingZeros() + { + String intValStr = intVal.toString(); + int newScale = scale; + int pointer = intValStr.length() - 1; + // This loop adjusts pointer which will be used to give us the substring + // of intValStr to use in our new BigDecimal, and also accordingly + // adjusts the scale of our new BigDecimal. + while (intValStr.charAt(pointer) == '0') + { + pointer --; + newScale --; + } + // Create a new BigDecimal with the appropriate substring and then + // set its scale. + BigDecimal result = new BigDecimal(intValStr.substring(0, pointer + 1)); + result.scale = newScale; + return result; + } + + public long longValue () + { + return toBigInteger().longValue(); + } + + public float floatValue() + { + return Float.valueOf(toString()).floatValue(); + } + + public double doubleValue() + { + return Double.valueOf(toString()).doubleValue(); + } + + public BigDecimal setScale (int scale) //throws ArithmeticException + { + return setScale (scale, ROUND_UNNECESSARY); + } + + public BigDecimal setScale (int scale, int roundingMode) + //throws ArithmeticException, IllegalArgumentException + { + // NOTE: The 1.5 JRE doesn't throw this, ones prior to it do and + // the spec says it should. Nevertheless, if 1.6 doesn't fix this + // we should consider removing it. + if( scale < 0 ) throw new Error/*ArithmeticException*/("Scale parameter < 0."); + return divide (ONE, scale, roundingMode); + } + + /** + * Returns a BigDecimal whose value is the same as this BigDecimal but whose + * representation has a scale of newScale. If the scale is + * reduced then rounding may occur, according to the RoundingMode. + * @param newScale + * @param roundingMode + * @return a BigDecimal whose scale is as given, whose value is + * this with possible rounding + * @throws ArithmeticException if the rounding mode is UNNECESSARY but + * rounding is required + * @since 1.5 + */ + /*public BigDecimal setScale(int newScale, RoundingMode roundingMode) + { + return setScale(newScale, roundingMode.ordinal()); + }*/ + + /** + * Returns a new BigDecimal constructed from the BigDecimal(String) + * constructor using the Double.toString(double) method to obtain + * the String. + * @param val the double value used in Double.toString(double) + * @return a BigDecimal representation of val + * @throws NumberFormatException if val is NaN or infinite + * @since 1.5 + */ + public static BigDecimal valueOf(double val) + { + if (Double.isInfinite(val) || Double.isNaN(val)) + throw new Error/*NumberFormatException*/("argument cannot be NaN or infinite."); + return new BigDecimal(Double.toString(val)); + } + + /** + * Returns a BigDecimal whose numerical value is the numerical value + * of this BigDecimal multiplied by 10 to the power of n. + * @param n the power of ten + * @return the new BigDecimal + * @since 1.5 + */ + public BigDecimal scaleByPowerOfTen(int n) + { + BigDecimal result = new BigDecimal(intVal, scale - n); + result.precision = precision; + return result; + } + + /** + * Returns a BigDecimal whose value is this to the power of + * n. + * @param n the power + * @return the new BigDecimal + * @since 1.5 + */ + public BigDecimal pow(int n) + { + if (n < 0 || n > 999999999) + throw new Error/*ArithmeticException*/("n must be between 0 and 999999999"); + BigDecimal result = new BigDecimal(intVal.pow(n), scale * n); + return result; + } + + /** + * Returns a BigDecimal whose value is determined by first calling pow(n) + * and then by rounding according to the MathContext mc. + * @param n the power + * @param mc the MathContext + * @return the new BigDecimal + * @throws ArithmeticException if n < 0 or n > 999999999 or if the result is + * inexact but the rounding is RoundingMode.UNNECESSARY + * @since 1.5 + */ + /*public BigDecimal pow(int n, MathContext mc) + { + // FIXME: The specs claim to use the X3.274-1996 algorithm. We + // currently do not. + return pow(n).round(mc); + }*/ + + /** + * Returns a BigDecimal whose value is the absolute value of this BigDecimal + * with rounding according to the given MathContext. + * @param mc the MathContext + * @return the new BigDecimal + */ + /*public BigDecimal abs(MathContext mc) + { + BigDecimal result = abs(); + result = result.round(mc); + return result; + }*/ + + /** + * Returns the size of a unit in the last place of this BigDecimal. This + * returns a BigDecimal with [unscaledValue, scale] = [1, this.scale()]. + * @return the size of a unit in the last place of this. + * @since 1.5 + */ + public BigDecimal ulp() + { + return new BigDecimal(BigInteger.ONE, scale); + } + + /** + * Converts this BigDecimal to a long value. + * @return the long value + * @throws ArithmeticException if rounding occurs or if overflow occurs + * @since 1.5 + */ + public long longValueExact() + { + // Set scale will throw an exception if rounding occurs. + BigDecimal temp = setScale(0, ROUND_UNNECESSARY); + BigInteger tempVal = temp.intVal; + // Check for overflow. + long result = intVal.longValue(); + if (tempVal.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 1 + || (result < 0 && signum() == 1) || (result > 0 && signum() == -1)) + throw new Error/*ArithmeticException*/("this BigDecimal is too " + + "large to fit into the return type"); + + return intVal.longValue(); + } + + /** + * Converts this BigDecimal into an int by first calling longValueExact + * and then checking that the long returned from that + * method fits into an int. + * @return an int whose value is this + * @throws ArithmeticException if this BigDecimal has a fractional part + * or is too large to fit into an int. + * @since 1.5 + */ + public int intValueExact() + { + long temp = longValueExact(); + int result = (int)temp; + if (result != temp) + throw new Error/*ArithmeticException*/ ("this BigDecimal cannot fit into an int"); + return result; + } + + /** + * Converts this BigDecimal into a byte by first calling longValueExact + * and then checking that the long returned from that + * method fits into a byte. + * @return a byte whose value is this + * @throws ArithmeticException if this BigDecimal has a fractional part + * or is too large to fit into a byte. + * @since 1.5 + */ + public byte byteValueExact() + { + long temp = longValueExact(); + byte result = (byte)temp; + if (result != temp) + throw new Error/*ArithmeticException*/ ("this BigDecimal cannot fit into a byte"); + return result; + } + + /** + * Converts this BigDecimal into a short by first calling longValueExact + * and then checking that the long returned from that + * method fits into a short. + * @return a short whose value is this + * @throws ArithmeticException if this BigDecimal has a fractional part + * or is too large to fit into a short. + * @since 1.5 + */ + public short shortValueExact() + { + long temp = longValueExact(); + short result = (short)temp; + if (result != temp) + throw new Error/*ArithmeticException*/ ("this BigDecimal cannot fit into a short"); + return result; + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/BigInteger.java b/Robust/src/ClassLibrary/MGC/gnu/BigInteger.java new file mode 100644 index 00000000..4dd41fae --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/BigInteger.java @@ -0,0 +1,2676 @@ +/* java.math.BigInteger -- Arbitary precision integers + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.math; + +/*import gnu.classpath.Configuration; + +import gnu.java.lang.CPStringBuilder; +import gnu.java.math.GMP; +import gnu.java.math.MPN; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.Random; +import java.util.logging.Logger; +*/ +/** + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998) and + * "Applied Cryptography, Second Edition" by Bruce Schneier (Wiley, 1996). + * + * Based primarily on IntNum.java BitOps.java by Per Bothner (per@bothner.com) + * (found in Kawa 1.6.62). + * + * @author Warren Levy (warrenl@cygnus.com) + * @date December 20, 1999. + * @status believed complete and correct. + */ +public class BigInteger //extends Number implements Comparable +{ + //private static final Logger log = Logger.getLogger(BigInteger.class.getName()); + + /** All integers are stored in 2's-complement form. + * If words == null, the ival is the value of this BigInteger. + * Otherwise, the first ival elements of words make the value + * of this BigInteger, stored in little-endian order, 2's-complement form. */ + private transient int ival; + private transient int[] words; + + // Serialization fields. + // the first three, although not used in the code, are present for + // compatibility with older RI versions of this class. DO NOT REMOVE. + private int bitCount = -1; + private int bitLength = -1; + private int lowestSetBit = -2; + private byte[] magnitude; + private int signum; + private static final long serialVersionUID = -8287574255936472291L; + + + /** We pre-allocate integers in the range minFixNum..maxFixNum. + * Note that we must at least preallocate 0, 1, and 10. */ + private static final int minFixNum = -100; + private static final int maxFixNum = 1024; + private static final int numFixNum = maxFixNum-minFixNum+1; + private static final BigInteger[] smallFixNums; + + /** The alter-ego GMP instance for this. */ + //private transient GMP mpz; + + /*private static final boolean USING_NATIVE = Configuration.WANT_NATIVE_BIG_INTEGER + && initializeLibrary();*/ + + static + { + /*if (USING_NATIVE) + { + smallFixNums = null; + ZERO = valueOf(0L); + ONE = valueOf(1L); + TEN = valueOf(10L); + } + else*/ + { + smallFixNums = new BigInteger[numFixNum]; + for (int i = numFixNum; --i >= 0; ) + smallFixNums[i] = new BigInteger(i + minFixNum); + + ZERO = smallFixNums[-minFixNum]; + ONE = smallFixNums[1 - minFixNum]; + TEN = smallFixNums[10 - minFixNum]; + } + } + + /** + * The constant zero as a BigInteger. + * @since 1.2 + */ + public static final BigInteger ZERO; + + /** + * The constant one as a BigInteger. + * @since 1.2 + */ + public static final BigInteger ONE; + + /** + * The constant ten as a BigInteger. + * @since 1.5 + */ + public static final BigInteger TEN; + + /* Rounding modes: */ + private static final int FLOOR = 1; + private static final int CEILING = 2; + private static final int TRUNCATE = 3; + private static final int ROUND = 4; + + /** When checking the probability of primes, it is most efficient to + * first check the factoring of small primes, so we'll use this array. + */ + private static final int[] primes = + { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, + 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, + 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, + 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251 }; + + /** HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Table 4.4. */ + private static final int[] k = + {100,150,200,250,300,350,400,500,600,800,1250, Integer.MAX_VALUE}; + private static final int[] t = + { 27, 18, 15, 12, 9, 8, 7, 6, 5, 4, 3, 2}; + + private BigInteger() + { + //super(); + + /*if (USING_NATIVE) + mpz = new GMP();*/ + } + + /* Create a new (non-shared) BigInteger, and initialize to an int. */ + private BigInteger(int value) + { + //super(); + + ival = value; + } + + public BigInteger(String s, int radix) + { + this(); + + int len = s.length(); + int i, digit; + boolean negative; + byte[] bytes; + char ch = s.charAt(0); + if (ch == '-') + { + negative = true; + i = 1; + bytes = new byte[len - 1]; + } + else + { + negative = false; + i = 0; + bytes = new byte[len]; + } + int byte_len = 0; + for ( ; i < len; i++) + { + ch = s.charAt(i); + digit = Character.digit(ch, radix); + if (digit < 0) + throw new Error/*NumberFormatException*/("Invalid character at position #" + i); + bytes[byte_len++] = (byte) digit; + } + + /*if (USING_NATIVE) + { + bytes = null; + if (mpz.fromString(s, radix) != 0) + throw new NumberFormatException("String \"" + s + + "\" is NOT a valid number in base " + + radix); + } + else*/ + { + BigInteger result; + // Testing (len < MPN.chars_per_word(radix)) would be more accurate, + // but slightly more expensive, for little practical gain. + if (len <= 15 && radix <= 16) + result = valueOf(Long.parseLong(s, radix)); + else + result = valueOf(bytes, byte_len, negative, radix); + + this.ival = result.ival; + this.words = result.words; + } + } + + public BigInteger(String val) + { + this(val, 10); + } + + /* Create a new (non-shared) BigInteger, and initialize from a byte array. */ + public BigInteger(byte[] val) + { + this(); + + if (val == null || val.length < 1) + throw new Error("Number Format Exception")/*NumberFormatException()*/; + + /*if (USING_NATIVE) + mpz.fromByteArray(val); + else*/ + { + words = byteArrayToIntArray(val, val[0] < 0 ? -1 : 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + } + } + + public BigInteger(int signum, byte[] magnitude) + { + this(); + + if (magnitude == null || signum > 1 || signum < -1) + throw new Error("Number Format Exception")/*NumberFormatException()*/; + + if (signum == 0) + { + int i; + for (i = magnitude.length - 1; i >= 0 && magnitude[i] == 0; --i) + ; + if (i >= 0) + throw new Error("Number Format Exception")/*NumberFormatException()*/; + return; + } + + /*if (USING_NATIVE) + mpz.fromSignedMagnitude(magnitude, signum == -1); + else*/ + { + // Magnitude is always positive, so don't ever pass a sign of -1. + words = byteArrayToIntArray(magnitude, 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + + if (signum < 0) + setNegative(); + } + } + + public BigInteger(int numBits, Random rnd) + { + this(); + + if (numBits < 0) + throw new Error("Illegal Argument Exception")/*IllegalArgumentException()*/; + + init(numBits, rnd); + } + + private void init(int numBits, Random rnd) + { + /*if (USING_NATIVE) + { + int length = (numBits + 7) / 8; + byte[] magnitude = new byte[length]; + rnd.nextBytes(magnitude); + int discardedBitCount = numBits % 8; + if (discardedBitCount != 0) + { + discardedBitCount = 8 - discardedBitCount; + magnitude[0] = (byte)((magnitude[0] & 0xFF) >>> discardedBitCount); + } + mpz.fromSignedMagnitude(magnitude, false); + magnitude = null; + return; + }*/ + + int highbits = numBits & 31; + // minimum number of bytes to store the above number of bits + int highBitByteCount = (highbits + 7) / 8; + // number of bits to discard from the last byte + int discardedBitCount = highbits % 8; + if (discardedBitCount != 0) + discardedBitCount = 8 - discardedBitCount; + byte[] highBitBytes = new byte[highBitByteCount]; + if (highbits > 0) + { + rnd.nextBytes(highBitBytes); + highbits = (highBitBytes[highBitByteCount - 1] & 0xFF) >>> discardedBitCount; + for (int i = highBitByteCount - 2; i >= 0; i--) + highbits = (highbits << 8) | (highBitBytes[i] & 0xFF); + } + int nwords = numBits / 32; + + while (highbits == 0 && nwords > 0) + { + highbits = rnd.nextInt(); + --nwords; + } + if (nwords == 0 && highbits >= 0) + { + ival = highbits; + } + else + { + ival = highbits < 0 ? nwords + 2 : nwords + 1; + words = new int[ival]; + words[nwords] = highbits; + while (--nwords >= 0) + words[nwords] = rnd.nextInt(); + } + } + + public BigInteger(int bitLength, int certainty, Random rnd) + { + this(); + + BigInteger result = new BigInteger(); + while (true) + { + result.init(bitLength, rnd); + result = result.setBit(bitLength - 1); + if (result.isProbablePrime(certainty)) + break; + } + + /*if (USING_NATIVE) + mpz.fromBI(result.mpz); + else*/ + { + this.ival = result.ival; + this.words = result.words; + } + } + + /** + * Return a BigInteger that is bitLength bits long with a + * probability < 2^-100 of being composite. + * + * @param bitLength length in bits of resulting number + * @param rnd random number generator to use + * @throws ArithmeticException if bitLength < 2 + * @since 1.4 + */ + public static BigInteger probablePrime(int bitLength, Random rnd) + { + if (bitLength < 2) + throw new Error("Arithmetic Exception")/*ArithmeticException()*/; + + return new BigInteger(bitLength, 100, rnd); + } + + /** Return a (possibly-shared) BigInteger with a given long value. */ + public static BigInteger valueOf(long val) + { + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + result.mpz.fromLong(val); + return result; + }*/ + + if (val >= minFixNum && val <= maxFixNum) + return smallFixNums[(int) val - minFixNum]; + int i = (int) val; + if ((long) i == val) + return new BigInteger(i); + BigInteger result = alloc(2); + result.ival = 2; + result.words[0] = i; + result.words[1] = (int)(val >> 32); + return result; + } + + /** + * @return true if the GMP-based native implementation library + * was successfully loaded. Returns false otherwise. + */ + /*private static boolean initializeLibrary() + { + boolean result; + try + { + System.loadLibrary("javamath"); + GMP.natInitializeLibrary(); + result = true; + } + catch (Throwable x) + { + result = false; + if (Configuration.DEBUG) + { + log.info("Unable to use native BigInteger: " + x); + log.info("Will use a pure Java implementation instead"); + } + } + return result; + }*/ + + /** Make a canonicalized BigInteger from an array of words. + * The array may be reused (without copying). */ + private static BigInteger make(int[] words, int len) + { + if (words == null) + return valueOf(len); + len = BigInteger.wordsNeeded(words, len); + if (len <= 1) + return len == 0 ? ZERO : valueOf(words[0]); + BigInteger num = new BigInteger(); + num.words = words; + num.ival = len; + return num; + } + + /** Convert a big-endian byte array to a little-endian array of words. */ + private static int[] byteArrayToIntArray(byte[] bytes, int sign) + { + // Determine number of words needed. + int[] words = new int[bytes.length/4 + 1]; + int nwords = words.length; + + // Create a int out of modulo 4 high order bytes. + int bptr = 0; + int word = sign; + for (int i = bytes.length % 4; i > 0; --i, bptr++) + word = (word << 8) | (bytes[bptr] & 0xff); + words[--nwords] = word; + + // Elements remaining in byte[] are a multiple of 4. + while (nwords > 0) + words[--nwords] = bytes[bptr++] << 24 | + (bytes[bptr++] & 0xff) << 16 | + (bytes[bptr++] & 0xff) << 8 | + (bytes[bptr++] & 0xff); + return words; + } + + /** Allocate a new non-shared BigInteger. + * @param nwords number of words to allocate + */ + private static BigInteger alloc(int nwords) + { + BigInteger result = new BigInteger(); + if (nwords > 1) + result.words = new int[nwords]; + return result; + } + + /** Change words.length to nwords. + * We allow words.length to be upto nwords+2 without reallocating. + */ + private void realloc(int nwords) + { + if (nwords == 0) + { + if (words != null) + { + if (ival > 0) + ival = words[0]; + words = null; + } + } + else if (words == null + || words.length < nwords + || words.length > nwords + 2) + { + int[] new_words = new int [nwords]; + if (words == null) + { + new_words[0] = ival; + ival = 1; + } + else + { + if (nwords < ival) + ival = nwords; + System.arraycopy(words, 0, new_words, 0, ival); + } + words = new_words; + } + } + + private boolean isNegative() + { + return (words == null ? ival : words[ival - 1]) < 0; + } + + public int signum() + { + /*if (USING_NATIVE) + return mpz.compare(ZERO.mpz);*/ + + if (ival == 0 && words == null) + return 0; + int top = words == null ? ival : words[ival-1]; + return top < 0 ? -1 : 1; + } + + private static int compareTo(BigInteger x, BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + return x.mpz.compare(y.mpz); + }*/ + + if (x.words == null && y.words == null) + return x.ival < y.ival ? -1 : x.ival > y.ival ? 1 : 0; + boolean x_negative = x.isNegative(); + boolean y_negative = y.isNegative(); + if (x_negative != y_negative) + return x_negative ? -1 : 1; + int x_len = x.words == null ? 1 : x.ival; + int y_len = y.words == null ? 1 : y.ival; + if (x_len != y_len) + return (x_len > y_len) != x_negative ? 1 : -1; + return MPN.cmp(x.words, y.words, x_len); + } + + /** @since 1.2 */ + public int compareTo(BigInteger val) + { + return compareTo(this, val); + } + + public BigInteger min(BigInteger val) + { + return compareTo(this, val) < 0 ? this : val; + } + + public BigInteger max(BigInteger val) + { + return compareTo(this, val) > 0 ? this : val; + } + + private boolean isZero() + { + return words == null && ival == 0; + } + + private boolean isOne() + { + return words == null && ival == 1; + } + + /** Calculate how many words are significant in words[0:len-1]. + * Returns the least value x such that x>0 && words[0:x-1]==words[0:len-1], + * when words is viewed as a 2's complement integer. + */ + private static int wordsNeeded(int[] words, int len) + { + int i = len; + if (i > 0) + { + int word = words[--i]; + if (word == -1) + { + while (i > 0 && (word = words[i - 1]) < 0) + { + i--; + if (word != -1) break; + } + } + else + { + while (word == 0 && i > 0 && (word = words[i - 1]) >= 0) i--; + } + } + return i + 1; + } + + private BigInteger canonicalize() + { + if (words != null + && (ival = BigInteger.wordsNeeded(words, ival)) <= 1) + { + if (ival == 1) + ival = words[0]; + words = null; + } + if (words == null && ival >= minFixNum && ival <= maxFixNum) + return smallFixNums[ival - minFixNum]; + return this; + } + + /** Add two ints, yielding a BigInteger. */ + private static BigInteger add(int x, int y) + { + return valueOf((long) x + (long) y); + } + + /** Add a BigInteger and an int, yielding a new BigInteger. */ + private static BigInteger add(BigInteger x, int y) + { + if (x.words == null) + return BigInteger.add(x.ival, y); + BigInteger result = new BigInteger(0); + result.setAdd(x, y); + return result.canonicalize(); + } + + /** Set this to the sum of x and y. + * OK if x==this. */ + private void setAdd(BigInteger x, int y) + { + if (x.words == null) + { + set((long) x.ival + (long) y); + return; + } + int len = x.ival; + realloc(len + 1); + long carry = y; + for (int i = 0; i < len; i++) + { + carry += ((long) x.words[i] & 0xffffffffL); + words[i] = (int) carry; + carry >>= 32; + } + if (x.words[len - 1] < 0) + carry--; + words[len] = (int) carry; + ival = wordsNeeded(words, len + 1); + } + + /** Destructively add an int to this. */ + private void setAdd(int y) + { + setAdd(this, y); + } + + /** Destructively set the value of this to a long. */ + private void set(long y) + { + int i = (int) y; + if ((long) i == y) + { + ival = i; + words = null; + } + else + { + realloc(2); + words[0] = i; + words[1] = (int) (y >> 32); + ival = 2; + } + } + + /** Destructively set the value of this to the given words. + * The words array is reused, not copied. */ + private void set(int[] words, int length) + { + this.ival = length; + this.words = words; + } + + /** Destructively set the value of this to that of y. */ + private void set(BigInteger y) + { + if (y.words == null) + set(y.ival); + else if (this != y) + { + realloc(y.ival); + System.arraycopy(y.words, 0, words, 0, y.ival); + ival = y.ival; + } + } + + /** Add two BigIntegers, yielding their sum as another BigInteger. */ + private static BigInteger add(BigInteger x, BigInteger y, int k) + { + if (x.words == null && y.words == null) + return valueOf((long) k * (long) y.ival + (long) x.ival); + if (k != 1) + { + if (k == -1) + y = BigInteger.neg(y); + else + y = BigInteger.times(y, valueOf(k)); + } + if (x.words == null) + return BigInteger.add(y, x.ival); + if (y.words == null) + return BigInteger.add(x, y.ival); + // Both are big + if (y.ival > x.ival) + { // Swap so x is longer then y. + BigInteger tmp = x; x = y; y = tmp; + } + BigInteger result = alloc(x.ival + 1); + int i = y.ival; + long carry = MPN.add_n(result.words, x.words, y.words, i); + long y_ext = y.words[i - 1] < 0 ? 0xffffffffL : 0; + for (; i < x.ival; i++) + { + carry += ((long) x.words[i] & 0xffffffffL) + y_ext; + result.words[i] = (int) carry; + carry >>>= 32; + } + if (x.words[i - 1] < 0) + y_ext--; + result.words[i] = (int) (carry + y_ext); + result.ival = i+1; + return result.canonicalize(); + } + + public BigInteger add(BigInteger val) + { + /*if (USING_NATIVE) + { + int dummy = val.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.add(val.mpz, result.mpz); + return result; + }*/ + + return add(this, val, 1); + } + + public BigInteger subtract(BigInteger val) + { + /*if (USING_NATIVE) + { + int dummy = val.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.subtract(val.mpz, result.mpz); + return result; + }*/ + + return add(this, val, -1); + } + + private static BigInteger times(BigInteger x, int y) + { + if (y == 0) + return ZERO; + if (y == 1) + return x; + int[] xwords = x.words; + int xlen = x.ival; + if (xwords == null) + return valueOf((long) xlen * (long) y); + boolean negative; + BigInteger result = BigInteger.alloc(xlen + 1); + if (xwords[xlen - 1] < 0) + { + negative = true; + negate(result.words, xwords, xlen); + xwords = result.words; + } + else + negative = false; + if (y < 0) + { + negative = !negative; + y = -y; + } + result.words[xlen] = MPN.mul_1(result.words, xwords, xlen, y); + result.ival = xlen + 1; + if (negative) + result.setNegative(); + return result.canonicalize(); + } + + private static BigInteger times(BigInteger x, BigInteger y) + { + if (y.words == null) + return times(x, y.ival); + if (x.words == null) + return times(y, x.ival); + boolean negative = false; + int[] xwords; + int[] ywords; + int xlen = x.ival; + int ylen = y.ival; + if (x.isNegative()) + { + negative = true; + xwords = new int[xlen]; + negate(xwords, x.words, xlen); + } + else + { + negative = false; + xwords = x.words; + } + if (y.isNegative()) + { + negative = !negative; + ywords = new int[ylen]; + negate(ywords, y.words, ylen); + } + else + ywords = y.words; + // Swap if x is shorter then y. + if (xlen < ylen) + { + int[] twords = xwords; xwords = ywords; ywords = twords; + int tlen = xlen; xlen = ylen; ylen = tlen; + } + BigInteger result = BigInteger.alloc(xlen+ylen); + MPN.mul(result.words, xwords, xlen, ywords, ylen); + result.ival = xlen+ylen; + if (negative) + result.setNegative(); + return result.canonicalize(); + } + + public BigInteger multiply(BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.multiply(y.mpz, result.mpz); + return result; + }*/ + + return times(this, y); + } + + private static void divide(long x, long y, + BigInteger quotient, BigInteger remainder, + int rounding_mode) + { + boolean xNegative, yNegative; + if (x < 0) + { + xNegative = true; + if (x == Long.MIN_VALUE) + { + divide(valueOf(x), valueOf(y), + quotient, remainder, rounding_mode); + return; + } + x = -x; + } + else + xNegative = false; + + if (y < 0) + { + yNegative = true; + if (y == Long.MIN_VALUE) + { + if (rounding_mode == TRUNCATE) + { // x != Long.Min_VALUE implies abs(x) < abs(y) + if (quotient != null) + quotient.set(0); + if (remainder != null) + remainder.set(x); + } + else + divide(valueOf(x), valueOf(y), + quotient, remainder, rounding_mode); + return; + } + y = -y; + } + else + yNegative = false; + + long q = x / y; + long r = x % y; + boolean qNegative = xNegative ^ yNegative; + + boolean add_one = false; + if (r != 0) + { + switch (rounding_mode) + { + case TRUNCATE: + break; + case CEILING: + case FLOOR: + if (qNegative == (rounding_mode == FLOOR)) + add_one = true; + break; + case ROUND: + add_one = r > ((y - (q & 1)) >> 1); + break; + } + } + if (quotient != null) + { + if (add_one) + q++; + if (qNegative) + q = -q; + quotient.set(q); + } + if (remainder != null) + { + // The remainder is by definition: X-Q*Y + if (add_one) + { + // Subtract the remainder from Y. + r = y - r; + // In this case, abs(Q*Y) > abs(X). + // So sign(remainder) = -sign(X). + xNegative = ! xNegative; + } + else + { + // If !add_one, then: abs(Q*Y) <= abs(X). + // So sign(remainder) = sign(X). + } + if (xNegative) + r = -r; + remainder.set(r); + } + } + + /** Divide two integers, yielding quotient and remainder. + * @param x the numerator in the division + * @param y the denominator in the division + * @param quotient is set to the quotient of the result (iff quotient!=null) + * @param remainder is set to the remainder of the result + * (iff remainder!=null) + * @param rounding_mode one of FLOOR, CEILING, TRUNCATE, or ROUND. + */ + private static void divide(BigInteger x, BigInteger y, + BigInteger quotient, BigInteger remainder, + int rounding_mode) + { + if ((x.words == null || x.ival <= 2) + && (y.words == null || y.ival <= 2)) + { + long x_l = x.longValue(); + long y_l = y.longValue(); + if (x_l != Long.MIN_VALUE && y_l != Long.MIN_VALUE) + { + divide(x_l, y_l, quotient, remainder, rounding_mode); + return; + } + } + + boolean xNegative = x.isNegative(); + boolean yNegative = y.isNegative(); + boolean qNegative = xNegative ^ yNegative; + + int ylen = y.words == null ? 1 : y.ival; + int[] ywords = new int[ylen]; + y.getAbsolute(ywords); + while (ylen > 1 && ywords[ylen - 1] == 0) ylen--; + + int xlen = x.words == null ? 1 : x.ival; + int[] xwords = new int[xlen+2]; + x.getAbsolute(xwords); + while (xlen > 1 && xwords[xlen-1] == 0) xlen--; + + int qlen, rlen; + + int cmpval = MPN.cmp(xwords, xlen, ywords, ylen); + if (cmpval < 0) // abs(x) < abs(y) + { // quotient = 0; remainder = num. + int[] rwords = xwords; xwords = ywords; ywords = rwords; + rlen = xlen; qlen = 1; xwords[0] = 0; + } + else if (cmpval == 0) // abs(x) == abs(y) + { + xwords[0] = 1; qlen = 1; // quotient = 1 + ywords[0] = 0; rlen = 1; // remainder = 0; + } + else if (ylen == 1) + { + qlen = xlen; + // Need to leave room for a word of leading zeros if dividing by 1 + // and the dividend has the high bit set. It might be safe to + // increment qlen in all cases, but it certainly is only necessary + // in the following case. + if (ywords[0] == 1 && xwords[xlen-1] < 0) + qlen++; + rlen = 1; + ywords[0] = MPN.divmod_1(xwords, xwords, xlen, ywords[0]); + } + else // abs(x) > abs(y) + { + // Normalize the denominator, i.e. make its most significant bit set by + // shifting it normalization_steps bits to the left. Also shift the + // numerator the same number of steps (to keep the quotient the same!). + + int nshift = MPN.count_leading_zeros(ywords[ylen - 1]); + if (nshift != 0) + { + // Shift up the denominator setting the most significant bit of + // the most significant word. + MPN.lshift(ywords, 0, ywords, ylen, nshift); + + // Shift up the numerator, possibly introducing a new most + // significant word. + int x_high = MPN.lshift(xwords, 0, xwords, xlen, nshift); + xwords[xlen++] = x_high; + } + + if (xlen == ylen) + xwords[xlen++] = 0; + MPN.divide(xwords, xlen, ywords, ylen); + rlen = ylen; + MPN.rshift0 (ywords, xwords, 0, rlen, nshift); + + qlen = xlen + 1 - ylen; + if (quotient != null) + { + for (int i = 0; i < qlen; i++) + xwords[i] = xwords[i+ylen]; + } + } + + if (ywords[rlen-1] < 0) + { + ywords[rlen] = 0; + rlen++; + } + + // Now the quotient is in xwords, and the remainder is in ywords. + + boolean add_one = false; + if (rlen > 1 || ywords[0] != 0) + { // Non-zero remainder i.e. in-exact quotient. + switch (rounding_mode) + { + case TRUNCATE: + break; + case CEILING: + case FLOOR: + if (qNegative == (rounding_mode == FLOOR)) + add_one = true; + break; + case ROUND: + // int cmp = compareTo(remainder<<1, abs(y)); + BigInteger tmp = remainder == null ? new BigInteger() : remainder; + tmp.set(ywords, rlen); + tmp = shift(tmp, 1); + if (yNegative) + tmp.setNegative(); + int cmp = compareTo(tmp, y); + // Now cmp == compareTo(sign(y)*(remainder<<1), y) + if (yNegative) + cmp = -cmp; + add_one = (cmp == 1) || (cmp == 0 && (xwords[0]&1) != 0); + } + } + if (quotient != null) + { + quotient.set(xwords, qlen); + if (qNegative) + { + if (add_one) // -(quotient + 1) == ~(quotient) + quotient.setInvert(); + else + quotient.setNegative(); + } + else if (add_one) + quotient.setAdd(1); + } + if (remainder != null) + { + // The remainder is by definition: X-Q*Y + remainder.set(ywords, rlen); + if (add_one) + { + // Subtract the remainder from Y: + // abs(R) = abs(Y) - abs(orig_rem) = -(abs(orig_rem) - abs(Y)). + BigInteger tmp; + if (y.words == null) + { + tmp = remainder; + tmp.set(yNegative ? ywords[0] + y.ival : ywords[0] - y.ival); + } + else + tmp = BigInteger.add(remainder, y, yNegative ? 1 : -1); + // Now tmp <= 0. + // In this case, abs(Q) = 1 + floor(abs(X)/abs(Y)). + // Hence, abs(Q*Y) > abs(X). + // So sign(remainder) = -sign(X). + if (xNegative) + remainder.setNegative(tmp); + else + remainder.set(tmp); + } + else + { + // If !add_one, then: abs(Q*Y) <= abs(X). + // So sign(remainder) = sign(X). + if (xNegative) + remainder.setNegative(); + } + } + } + + public BigInteger divide(BigInteger val) + { + /*if (USING_NATIVE) + { + if (val.compareTo(ZERO) == 0) + throw new ArithmeticException("divisor is zero"); + + BigInteger result = new BigInteger(); + mpz.quotient(val.mpz, result.mpz); + return result; + }*/ + + if (val.isZero()) + throw new Error/*ArithmeticException*/("divisor is zero"); + + BigInteger quot = new BigInteger(); + divide(this, val, quot, null, TRUNCATE); + return quot.canonicalize(); + } + + public BigInteger remainder(BigInteger val) + { + /*if (USING_NATIVE) + { + if (val.compareTo(ZERO) == 0) + throw new ArithmeticException("divisor is zero"); + + BigInteger result = new BigInteger(); + mpz.remainder(val.mpz, result.mpz); + return result; + }*/ + + if (val.isZero()) + throw new Error/*ArithmeticException*/("divisor is zero"); + + BigInteger rem = new BigInteger(); + divide(this, val, null, rem, TRUNCATE); + return rem.canonicalize(); + } + + public BigInteger[] divideAndRemainder(BigInteger val) + { + /*if (USING_NATIVE) + { + if (val.compareTo(ZERO) == 0) + throw new ArithmeticException("divisor is zero"); + + BigInteger q = new BigInteger(); + BigInteger r = new BigInteger(); + mpz.quotientAndRemainder(val.mpz, q.mpz, r.mpz); + return new BigInteger[] { q, r }; + }*/ + + if (val.isZero()) + throw new Error/*ArithmeticException*/("divisor is zero"); + + BigInteger[] result = new BigInteger[2]; + result[0] = new BigInteger(); + result[1] = new BigInteger(); + divide(this, val, result[0], result[1], TRUNCATE); + result[0].canonicalize(); + result[1].canonicalize(); + return result; + } + + public BigInteger mod(BigInteger m) + { + /*if (USING_NATIVE) + { + int dummy = m.signum; // force NPE check + if (m.compareTo(ZERO) < 1) + throw new ArithmeticException("non-positive modulus"); + + BigInteger result = new BigInteger(); + mpz.modulo(m.mpz, result.mpz); + return result; + }*/ + + if (m.isNegative() || m.isZero()) + throw new Error/*ArithmeticException*/("non-positive modulus"); + + BigInteger rem = new BigInteger(); + divide(this, m, null, rem, FLOOR); + return rem.canonicalize(); + } + + /** Calculate the integral power of a BigInteger. + * @param exponent the exponent (must be non-negative) + */ + public BigInteger pow(int exponent) + { + if (exponent <= 0) + { + if (exponent == 0) + return ONE; + throw new Error/*ArithmeticException*/("negative exponent"); + } + + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.pow(exponent, result.mpz); + return result; + }*/ + + if (isZero()) + return this; + int plen = words == null ? 1 : ival; // Length of pow2. + int blen = ((bitLength() * exponent) >> 5) + 2 * plen; + boolean negative = isNegative() && (exponent & 1) != 0; + int[] pow2 = new int [blen]; + int[] rwords = new int [blen]; + int[] work = new int [blen]; + getAbsolute(pow2); // pow2 = abs(this); + int rlen = 1; + rwords[0] = 1; // rwords = 1; + for (;;) // for (i = 0; ; i++) + { + // pow2 == this**(2**i) + // prod = this**(sum(j=0..i-1, (exponent>>j)&1)) + if ((exponent & 1) != 0) + { // r *= pow2 + MPN.mul(work, pow2, plen, rwords, rlen); + int[] temp = work; work = rwords; rwords = temp; + rlen += plen; + while (rwords[rlen - 1] == 0) rlen--; + } + exponent >>= 1; + if (exponent == 0) + break; + // pow2 *= pow2; + MPN.mul(work, pow2, plen, pow2, plen); + int[] temp = work; work = pow2; pow2 = temp; // swap to avoid a copy + plen *= 2; + while (pow2[plen - 1] == 0) plen--; + } + if (rwords[rlen - 1] < 0) + rlen++; + if (negative) + negate(rwords, rwords, rlen); + return BigInteger.make(rwords, rlen); + } + + private static int[] euclidInv(int a, int b, int prevDiv) + { + if (b == 0) + throw new Error/*ArithmeticException*/("not invertible"); + + if (b == 1) + // Success: values are indeed invertible! + // Bottom of the recursion reached; start unwinding. + return new int[] { -prevDiv, 1 }; + + int[] xy = euclidInv(b, a % b, a / b); // Recursion happens here. + a = xy[0]; // use our local copy of 'a' as a work var + xy[0] = a * -prevDiv + xy[1]; + xy[1] = a; + return xy; + } + + private static void euclidInv(BigInteger a, BigInteger b, + BigInteger prevDiv, BigInteger[] xy) + { + if (b.isZero()) + throw new Error/*ArithmeticException*/("not invertible"); + + if (b.isOne()) + { + // Success: values are indeed invertible! + // Bottom of the recursion reached; start unwinding. + xy[0] = neg(prevDiv); + xy[1] = ONE; + return; + } + + // Recursion happens in the following conditional! + + // If a just contains an int, then use integer math for the rest. + if (a.words == null) + { + int[] xyInt = euclidInv(b.ival, a.ival % b.ival, a.ival / b.ival); + xy[0] = new BigInteger(xyInt[0]); + xy[1] = new BigInteger(xyInt[1]); + } + else + { + BigInteger rem = new BigInteger(); + BigInteger quot = new BigInteger(); + divide(a, b, quot, rem, FLOOR); + // quot and rem may not be in canonical form. ensure + rem.canonicalize(); + quot.canonicalize(); + euclidInv(b, rem, quot, xy); + } + + BigInteger t = xy[0]; + xy[0] = add(xy[1], times(t, prevDiv), -1); + xy[1] = t; + } + + public BigInteger modInverse(BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + if (mpz.compare(ZERO.mpz) < 1) + throw new ArithmeticException("non-positive modulo"); + + BigInteger result = new BigInteger(); + mpz.modInverse(y.mpz, result.mpz); + return result; + }*/ + + if (y.isNegative() || y.isZero()) + throw new Error/*ArithmeticException*/("non-positive modulo"); + + // Degenerate cases. + if (y.isOne()) + return ZERO; + if (isOne()) + return ONE; + + // Use Euclid's algorithm as in gcd() but do this recursively + // rather than in a loop so we can use the intermediate results as we + // unwind from the recursion. + // Used http://www.math.nmsu.edu/~crypto/EuclideanAlgo.html as reference. + BigInteger result = new BigInteger(); + boolean swapped = false; + + if (y.words == null) + { + // The result is guaranteed to be less than the modulus, y (which is + // an int), so simplify this by working with the int result of this + // modulo y. Also, if this is negative, make it positive via modulo + // math. Note that BigInteger.mod() must be used even if this is + // already an int as the % operator would provide a negative result if + // this is negative, BigInteger.mod() never returns negative values. + int xval = (words != null || isNegative()) ? mod(y).ival : ival; + int yval = y.ival; + + // Swap values so x > y. + if (yval > xval) + { + int tmp = xval; xval = yval; yval = tmp; + swapped = true; + } + // Normally, the result is in the 2nd element of the array, but + // if originally x < y, then x and y were swapped and the result + // is in the 1st element of the array. + result.ival = + euclidInv(yval, xval % yval, xval / yval)[swapped ? 0 : 1]; + + // Result can't be negative, so make it positive by adding the + // original modulus, y.ival (not the possibly "swapped" yval). + if (result.ival < 0) + result.ival += y.ival; + } + else + { + // As above, force this to be a positive value via modulo math. + BigInteger x = isNegative() ? this.mod(y) : this; + + // Swap values so x > y. + if (x.compareTo(y) < 0) + { + result = x; x = y; y = result; // use 'result' as a work var + swapped = true; + } + // As above (for ints), result will be in the 2nd element unless + // the original x and y were swapped. + BigInteger rem = new BigInteger(); + BigInteger quot = new BigInteger(); + divide(x, y, quot, rem, FLOOR); + // quot and rem may not be in canonical form. ensure + rem.canonicalize(); + quot.canonicalize(); + BigInteger[] xy = new BigInteger[2]; + euclidInv(y, rem, quot, xy); + result = swapped ? xy[0] : xy[1]; + + // Result can't be negative, so make it positive by adding the + // original modulus, y (which is now x if they were swapped). + if (result.isNegative()) + result = add(result, swapped ? x : y, 1); + } + + return result; + } + + public BigInteger modPow(BigInteger exponent, BigInteger m) + { + /*if (USING_NATIVE) + { + int dummy = exponent.signum; // force NPE check + if (m.mpz.compare(ZERO.mpz) < 1) + throw new ArithmeticException("non-positive modulo"); + + BigInteger result = new BigInteger(); + mpz.modPow(exponent.mpz, m.mpz, result.mpz); + return result; + }*/ + + if (m.isNegative() || m.isZero()) + throw new Error/*ArithmeticException*/("non-positive modulo"); + + if (exponent.isNegative()) + return modInverse(m).modPow(exponent.negate(), m); + if (exponent.isOne()) + return mod(m); + + // To do this naively by first raising this to the power of exponent + // and then performing modulo m would be extremely expensive, especially + // for very large numbers. The solution is found in Number Theory + // where a combination of partial powers and moduli can be done easily. + // + // We'll use the algorithm for Additive Chaining which can be found on + // p. 244 of "Applied Cryptography, Second Edition" by Bruce Schneier. + BigInteger s = ONE; + BigInteger t = this; + BigInteger u = exponent; + + while (!u.isZero()) + { + if (u.and(ONE).isOne()) + s = times(s, t).mod(m); + u = u.shiftRight(1); + t = times(t, t).mod(m); + } + + return s; + } + + /** Calculate Greatest Common Divisor for non-negative ints. */ + private static int gcd(int a, int b) + { + // Euclid's algorithm, copied from libg++. + int tmp; + if (b > a) + { + tmp = a; a = b; b = tmp; + } + for(;;) + { + if (b == 0) + return a; + if (b == 1) + return b; + tmp = b; + b = a % b; + a = tmp; + } + } + + public BigInteger gcd(BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.gcd(y.mpz, result.mpz); + return result; + }*/ + + int xval = ival; + int yval = y.ival; + if (words == null) + { + if (xval == 0) + return abs(y); + if (y.words == null + && xval != Integer.MIN_VALUE && yval != Integer.MIN_VALUE) + { + if (xval < 0) + xval = -xval; + if (yval < 0) + yval = -yval; + return valueOf(gcd(xval, yval)); + } + xval = 1; + } + if (y.words == null) + { + if (yval == 0) + return abs(this); + yval = 1; + } + int len = (xval > yval ? xval : yval) + 1; + int[] xwords = new int[len]; + int[] ywords = new int[len]; + getAbsolute(xwords); + y.getAbsolute(ywords); + len = MPN.gcd(xwords, ywords, len); + BigInteger result = new BigInteger(0); + result.ival = len; + result.words = xwords; + return result.canonicalize(); + } + + /** + *

Returns true if this BigInteger is probably prime, + * false if it's definitely composite. If certainty + * is <= 0, true is returned.

+ * + * @param certainty a measure of the uncertainty that the caller is willing + * to tolerate: if the call returns true the probability that + * this BigInteger is prime exceeds (1 - 1/2certainty). + * The execution time of this method is proportional to the value of this + * parameter. + * @return true if this BigInteger is probably prime, + * false if it's definitely composite. + */ + public boolean isProbablePrime(int certainty) + { + if (certainty < 1) + return true; + + /*if (USING_NATIVE) + return mpz.testPrimality(certainty) != 0;*/ + + /** We'll use the Rabin-Miller algorithm for doing a probabilistic + * primality test. It is fast, easy and has faster decreasing odds of a + * composite passing than with other tests. This means that this + * method will actually have a probability much greater than the + * 1 - .5^certainty specified in the JCL (p. 117), but I don't think + * anyone will complain about better performance with greater certainty. + * + * The Rabin-Miller algorithm can be found on pp. 259-261 of "Applied + * Cryptography, Second Edition" by Bruce Schneier. + */ + + // First rule out small prime factors + BigInteger rem = new BigInteger(); + int i; + for (i = 0; i < primes.length; i++) + { + if (words == null && ival == primes[i]) + return true; + + divide(this, smallFixNums[primes[i] - minFixNum], null, rem, TRUNCATE); + if (rem.canonicalize().isZero()) + return false; + } + + // Now perform the Rabin-Miller test. + + // Set b to the number of times 2 evenly divides (this - 1). + // I.e. 2^b is the largest power of 2 that divides (this - 1). + BigInteger pMinus1 = add(this, -1); + int b = pMinus1.getLowestSetBit(); + + // Set m such that this = 1 + 2^b * m. + BigInteger m = pMinus1.divide(valueOf(2L).pow(b)); + + // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. Note + // 4.49 (controlling the error probability) gives the number of trials + // for an error probability of 1/2**80, given the number of bits in the + // number to test. we shall use these numbers as is if/when 'certainty' + // is less or equal to 80, and twice as much if it's greater. + int bits = this.bitLength(); + for (i = 0; i < k.length; i++) + if (bits <= k[i]) + break; + int trials = t[i]; + if (certainty > 80) + trials *= 2; + BigInteger z; + for (int t = 0; t < trials; t++) + { + // The HAC (Handbook of Applied Cryptography), Alfred Menezes & al. + // Remark 4.28 states: "...A strategy that is sometimes employed + // is to fix the bases a to be the first few primes instead of + // choosing them at random. + z = smallFixNums[primes[t] - minFixNum].modPow(m, this); + if (z.isOne() || z.equals(pMinus1)) + continue; // Passes the test; may be prime. + + for (i = 0; i < b; ) + { + if (z.isOne()) + return false; + i++; + if (z.equals(pMinus1)) + break; // Passes the test; may be prime. + + z = z.modPow(valueOf(2), this); + } + + if (i == b && !z.equals(pMinus1)) + return false; + } + return true; + } + + private void setInvert() + { + if (words == null) + ival = ~ival; + else + { + for (int i = ival; --i >= 0; ) + words[i] = ~words[i]; + } + } + + private void setShiftLeft(BigInteger x, int count) + { + int[] xwords; + int xlen; + if (x.words == null) + { + if (count < 32) + { + set((long) x.ival << count); + return; + } + xwords = new int[1]; + xwords[0] = x.ival; + xlen = 1; + } + else + { + xwords = x.words; + xlen = x.ival; + } + int word_count = count >> 5; + count &= 31; + int new_len = xlen + word_count; + if (count == 0) + { + realloc(new_len); + for (int i = xlen; --i >= 0; ) + words[i+word_count] = xwords[i]; + } + else + { + new_len++; + realloc(new_len); + int shift_out = MPN.lshift(words, word_count, xwords, xlen, count); + count = 32 - count; + words[new_len-1] = (shift_out << count) >> count; // sign-extend. + } + ival = new_len; + for (int i = word_count; --i >= 0; ) + words[i] = 0; + } + + private void setShiftRight(BigInteger x, int count) + { + if (x.words == null) + set(count < 32 ? x.ival >> count : x.ival < 0 ? -1 : 0); + else if (count == 0) + set(x); + else + { + boolean neg = x.isNegative(); + int word_count = count >> 5; + count &= 31; + int d_len = x.ival - word_count; + if (d_len <= 0) + set(neg ? -1 : 0); + else + { + if (words == null || words.length < d_len) + realloc(d_len); + MPN.rshift0 (words, x.words, word_count, d_len, count); + ival = d_len; + if (neg) + words[d_len-1] |= -2 << (31 - count); + } + } + } + + private void setShift(BigInteger x, int count) + { + if (count > 0) + setShiftLeft(x, count); + else + setShiftRight(x, -count); + } + + private static BigInteger shift(BigInteger x, int count) + { + if (x.words == null) + { + if (count <= 0) + return valueOf(count > -32 ? x.ival >> (-count) : x.ival < 0 ? -1 : 0); + if (count < 32) + return valueOf((long) x.ival << count); + } + if (count == 0) + return x; + BigInteger result = new BigInteger(0); + result.setShift(x, count); + return result.canonicalize(); + } + + public BigInteger shiftLeft(int n) + { + if (n == 0) + return this; + + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + if (n < 0) + mpz.shiftRight(-n, result.mpz); + else + mpz.shiftLeft(n, result.mpz); + return result; + }*/ + + return shift(this, n); + } + + public BigInteger shiftRight(int n) + { + if (n == 0) + return this; + + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + if (n < 0) + mpz.shiftLeft(-n, result.mpz); + else + mpz.shiftRight(n, result.mpz); + return result; + }*/ + + return shift(this, -n); + } + + /*private void format(int radix, CPStringBuilder buffer) + { + if (words == null) + buffer.append(Integer.toString(ival, radix)); + else if (ival <= 2) + buffer.append(Long.toString(longValue(), radix)); + else + { + boolean neg = isNegative(); + int[] work; + if (neg || radix != 16) + { + work = new int[ival]; + getAbsolute(work); + } + else + work = words; + int len = ival; + + if (radix == 16) + { + if (neg) + buffer.append('-'); + int buf_start = buffer.length(); + for (int i = len; --i >= 0; ) + { + int word = work[i]; + for (int j = 8; --j >= 0; ) + { + int hex_digit = (word >> (4 * j)) & 0xF; + // Suppress leading zeros: + if (hex_digit > 0 || buffer.length() > buf_start) + buffer.append(Character.forDigit(hex_digit, 16)); + } + } + } + else + { + int i = buffer.length(); + for (;;) + { + int digit = MPN.divmod_1(work, work, len, radix); + buffer.append(Character.forDigit(digit, radix)); + while (len > 0 && work[len-1] == 0) len--; + if (len == 0) + break; + } + if (neg) + buffer.append('-'); + // Reverse buffer. + int j = buffer.length() - 1; + while (i < j) + { + char tmp = buffer.charAt(i); + buffer.setCharAt(i, buffer.charAt(j)); + buffer.setCharAt(j, tmp); + i++; j--; + } + } + } + }*/ + + /*public String toString() + { + return toString(10); + }*/ + + /*public String toString(int radix) + { + if (USING_NATIVE) + return mpz.toString(radix); + + if (words == null) + return Integer.toString(ival, radix); + if (ival <= 2) + return Long.toString(longValue(), radix); + int buf_size = ival * (MPN.chars_per_word(radix) + 1); + CPStringBuilder buffer = new CPStringBuilder(buf_size); + format(radix, buffer); + return buffer.toString(); + }*/ + + public int intValue() + { + /*if (USING_NATIVE) + { + int result = mpz.absIntValue(); + return mpz.compare(ZERO.mpz) < 0 ? - result : result; + }*/ + + if (words == null) + return ival; + return words[0]; + } + + public long longValue() + { + /*if (USING_NATIVE) + { + long result; + result = (abs().shiftRight(32)).mpz.absIntValue(); + result <<= 32; + result |= mpz.absIntValue() & 0xFFFFFFFFL; + return this.compareTo(ZERO) < 0 ? - result : result; + }*/ + + if (words == null) + return ival; + if (ival == 1) + return words[0]; + return ((long)words[1] << 32) + ((long)words[0] & 0xffffffffL); + } + + public int hashCode() + { + // FIXME: May not match hashcode of JDK. + /*if (USING_NATIVE) + { + // TODO: profile to decide whether to make it native + byte[] bytes = this.toByteArray(); + int result = 0; + for (int i = 0; i < bytes.length; i++) + result ^= (bytes[i] & 0xFF) << (8 * (i % 4)); + return result; + }*/ + + return words == null ? ival : (words[0] + words[ival - 1]); + } + + /* Assumes x and y are both canonicalized. */ + private static boolean equals(BigInteger x, BigInteger y) + { + /*if (USING_NATIVE) + return x.mpz.compare(y.mpz) == 0;*/ + + if (x.words == null && y.words == null) + return x.ival == y.ival; + if (x.words == null || y.words == null || x.ival != y.ival) + return false; + for (int i = x.ival; --i >= 0; ) + { + if (x.words[i] != y.words[i]) + return false; + } + return true; + } + + /* Assumes this and obj are both canonicalized. */ + public boolean equals(Object obj) + { + if (! (obj instanceof BigInteger)) + return false; + return equals(this, (BigInteger) obj); + } + + private static BigInteger valueOf(byte[] digits, int byte_len, + boolean negative, int radix) + { + int chars_per_word = MPN.chars_per_word(radix); + int[] words = new int[byte_len / chars_per_word + 1]; + int size = MPN.set_str(words, digits, byte_len, radix); + if (size == 0) + return ZERO; + if (words[size-1] < 0) + words[size++] = 0; + if (negative) + negate(words, words, size); + return make(words, size); + } + + public double doubleValue() + { + /*if (USING_NATIVE) + return mpz.doubleValue();*/ + + if (words == null) + return (double) ival; + if (ival <= 2) + return (double) longValue(); + if (isNegative()) + return neg(this).roundToDouble(0, true, false); + return roundToDouble(0, false, false); + } + + public float floatValue() + { + return (float) doubleValue(); + } + + /** Return true if any of the lowest n bits are one. + * (false if n is negative). */ + private boolean checkBits(int n) + { + if (n <= 0) + return false; + if (words == null) + return n > 31 || ((ival & ((1 << n) - 1)) != 0); + int i; + for (i = 0; i < (n >> 5) ; i++) + if (words[i] != 0) + return true; + return (n & 31) != 0 && (words[i] & ((1 << (n & 31)) - 1)) != 0; + } + + /** Convert a semi-processed BigInteger to double. + * Number must be non-negative. Multiplies by a power of two, applies sign, + * and converts to double, with the usual java rounding. + * @param exp power of two, positive or negative, by which to multiply + * @param neg true if negative + * @param remainder true if the BigInteger is the result of a truncating + * division that had non-zero remainder. To ensure proper rounding in + * this case, the BigInteger must have at least 54 bits. */ + private double roundToDouble(int exp, boolean neg, boolean remainder) + { + // Compute length. + int il = bitLength(); + + // Exponent when normalized to have decimal point directly after + // leading one. This is stored excess 1023 in the exponent bit field. + exp += il - 1; + + // Gross underflow. If exp == -1075, we let the rounding + // computation determine whether it is minval or 0 (which are just + // 0x0000 0000 0000 0001 and 0x0000 0000 0000 0000 as bit + // patterns). + if (exp < -1075) + return neg ? -0.0 : 0.0; + + // gross overflow + if (exp > 1023) + return neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + + // number of bits in mantissa, including the leading one. + // 53 unless it's denormalized + int ml = (exp >= -1022 ? 53 : 53 + exp + 1022); + + // Get top ml + 1 bits. The extra one is for rounding. + long m; + int excess_bits = il - (ml + 1); + if (excess_bits > 0) + m = ((words == null) ? ival >> excess_bits + : MPN.rshift_long(words, ival, excess_bits)); + else + m = longValue() << (- excess_bits); + + // Special rounding for maxval. If the number exceeds maxval by + // any amount, even if it's less than half a step, it overflows. + if (exp == 1023 && ((m >> 1) == (1L << 53) - 1)) + { + if (remainder || checkBits(il - ml)) + return neg ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + else + return neg ? - Double.MAX_VALUE : Double.MAX_VALUE; + } + + // Normal round-to-even rule: round up if the bit dropped is a one, and + // the bit above it or any of the bits below it is a one. + if ((m & 1) == 1 + && ((m & 2) == 2 || remainder || checkBits(excess_bits))) + { + m += 2; + // Check if we overflowed the mantissa + if ((m & (1L << 54)) != 0) + { + exp++; + // renormalize + m >>= 1; + } + // Check if a denormalized mantissa was just rounded up to a + // normalized one. + else if (ml == 52 && (m & (1L << 53)) != 0) + exp++; + } + + // Discard the rounding bit + m >>= 1; + + long bits_sign = neg ? (1L << 63) : 0; + exp += 1023; + long bits_exp = (exp <= 0) ? 0 : ((long)exp) << 52; + long bits_mant = m & ~(1L << 52); + return Double.longBitsToDouble(bits_sign | bits_exp | bits_mant); + } + + /** Copy the abolute value of this into an array of words. + * Assumes words.length >= (this.words == null ? 1 : this.ival). + * Result is zero-extended, but need not be a valid 2's complement number. + */ + private void getAbsolute(int[] words) + { + int len; + if (this.words == null) + { + len = 1; + words[0] = this.ival; + } + else + { + len = this.ival; + for (int i = len; --i >= 0; ) + words[i] = this.words[i]; + } + if (words[len - 1] < 0) + negate(words, words, len); + for (int i = words.length; --i > len; ) + words[i] = 0; + } + + /** Set dest[0:len-1] to the negation of src[0:len-1]. + * Return true if overflow (i.e. if src is -2**(32*len-1)). + * Ok for src==dest. */ + private static boolean negate(int[] dest, int[] src, int len) + { + long carry = 1; + boolean negative = src[len-1] < 0; + for (int i = 0; i < len; i++) + { + carry += ((long) (~src[i]) & 0xffffffffL); + dest[i] = (int) carry; + carry >>= 32; + } + return (negative && dest[len-1] < 0); + } + + /** Destructively set this to the negative of x. + * It is OK if x==this.*/ + private void setNegative(BigInteger x) + { + int len = x.ival; + if (x.words == null) + { + if (len == Integer.MIN_VALUE) + set(- (long) len); + else + set(-len); + return; + } + realloc(len + 1); + if (negate(words, x.words, len)) + words[len++] = 0; + ival = len; + } + + /** Destructively negate this. */ + private void setNegative() + { + setNegative(this); + } + + private static BigInteger abs(BigInteger x) + { + return x.isNegative() ? neg(x) : x; + } + + public BigInteger abs() + { + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.abs(result.mpz); + return result; + }*/ + + return abs(this); + } + + private static BigInteger neg(BigInteger x) + { + if (x.words == null && x.ival != Integer.MIN_VALUE) + return valueOf(- x.ival); + BigInteger result = new BigInteger(0); + result.setNegative(x); + return result.canonicalize(); + } + + public BigInteger negate() + { + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.negate(result.mpz); + return result; + }*/ + + return neg(this); + } + + /** Calculates ceiling(log2(this < 0 ? -this : this+1)) + * See Common Lisp: the Language, 2nd ed, p. 361. + */ + public int bitLength() + { + /*if (USING_NATIVE) + return mpz.bitLength();*/ + + if (words == null) + return MPN.intLength(ival); + return MPN.intLength(words, ival); + } + + public byte[] toByteArray() + { + if (signum() == 0) + return new byte[1]; + + /*if (USING_NATIVE) + { + // the minimal number of bytes required to represent the MPI is function + // of (a) its bit-length, and (b) its sign. only when this MPI is both + // positive, and its bit-length is a multiple of 8 do we add one zero + // bit for its sign. we do this so if we construct a new MPI from the + // resulting byte array, we wouldn't mistake a positive number, whose + // bit-length is a multiple of 8, for a similar-length negative one. + int bits = bitLength(); + if (bits % 8 == 0 || this.signum() == 1) + bits++; + byte[] bytes = new byte[(bits + 7) / 8]; + mpz.toByteArray(bytes); + return bytes; + }*/ + + // Determine number of bytes needed. The method bitlength returns + // the size without the sign bit, so add one bit for that and then + // add 7 more to emulate the ceil function using integer math. + byte[] bytes = new byte[(bitLength() + 1 + 7) / 8]; + int nbytes = bytes.length; + + int wptr = 0; + int word; + + // Deal with words array until one word or less is left to process. + // If BigInteger is an int, then it is in ival and nbytes will be <= 4. + while (nbytes > 4) + { + word = words[wptr++]; + for (int i = 4; i > 0; --i, word >>= 8) + bytes[--nbytes] = (byte) word; + } + + // Deal with the last few bytes. If BigInteger is an int, use ival. + word = (words == null) ? ival : words[wptr]; + for ( ; nbytes > 0; word >>= 8) + bytes[--nbytes] = (byte) word; + + return bytes; + } + + /** Return the boolean opcode (for bitOp) for swapped operands. + * I.e. bitOp(swappedOp(op), x, y) == bitOp(op, y, x). + */ + private static int swappedOp(int op) + { + return + "\000\001\004\005\002\003\006\007\010\011\014\015\012\013\016\017" + .charAt(op); + } + + /** Do one the the 16 possible bit-wise operations of two BigIntegers. */ + private static BigInteger bitOp(int op, BigInteger x, BigInteger y) + { + switch (op) + { + case 0: return ZERO; + case 1: return x.and(y); + case 3: return x; + case 5: return y; + case 15: return valueOf(-1); + } + BigInteger result = new BigInteger(); + setBitOp(result, op, x, y); + return result.canonicalize(); + } + + /** Do one the the 16 possible bit-wise operations of two BigIntegers. */ + private static void setBitOp(BigInteger result, int op, + BigInteger x, BigInteger y) + { + if ((y.words != null) && (x.words == null || x.ival < y.ival)) + { + BigInteger temp = x; x = y; y = temp; + op = swappedOp(op); + } + int xi; + int yi; + int xlen, ylen; + if (y.words == null) + { + yi = y.ival; + ylen = 1; + } + else + { + yi = y.words[0]; + ylen = y.ival; + } + if (x.words == null) + { + xi = x.ival; + xlen = 1; + } + else + { + xi = x.words[0]; + xlen = x.ival; + } + if (xlen > 1) + result.realloc(xlen); + int[] w = result.words; + int i = 0; + // Code for how to handle the remainder of x. + // 0: Truncate to length of y. + // 1: Copy rest of x. + // 2: Invert rest of x. + int finish = 0; + int ni; + switch (op) + { + case 0: // clr + ni = 0; + break; + case 1: // and + for (;;) + { + ni = xi & yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 1; + break; + case 2: // andc2 + for (;;) + { + ni = xi & ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 1; + break; + case 3: // copy x + ni = xi; + finish = 1; // Copy rest + break; + case 4: // andc1 + for (;;) + { + ni = ~xi & yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 2; + break; + case 5: // copy y + for (;;) + { + ni = yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + break; + case 6: // xor + for (;;) + { + ni = xi ^ yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + finish = yi < 0 ? 2 : 1; + break; + case 7: // ior + for (;;) + { + ni = xi | yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 1; + break; + case 8: // nor + for (;;) + { + ni = ~(xi | yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 2; + break; + case 9: // eqv [exclusive nor] + for (;;) + { + ni = ~(xi ^ yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + finish = yi >= 0 ? 2 : 1; + break; + case 10: // c2 + for (;;) + { + ni = ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + break; + case 11: // orc2 + for (;;) + { + ni = xi | ~yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 1; + break; + case 12: // c1 + ni = ~xi; + finish = 2; + break; + case 13: // orc1 + for (;;) + { + ni = ~xi | yi; + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi >= 0) finish = 2; + break; + case 14: // nand + for (;;) + { + ni = ~(xi & yi); + if (i+1 >= ylen) break; + w[i++] = ni; xi = x.words[i]; yi = y.words[i]; + } + if (yi < 0) finish = 2; + break; + default: + case 15: // set + ni = -1; + break; + } + // Here i==ylen-1; w[0]..w[i-1] have the correct result; + // and ni contains the correct result for w[i+1]. + if (i+1 == xlen) + finish = 0; + switch (finish) + { + case 0: + if (i == 0 && w == null) + { + result.ival = ni; + return; + } + w[i++] = ni; + break; + case 1: w[i] = ni; while (++i < xlen) w[i] = x.words[i]; break; + case 2: w[i] = ni; while (++i < xlen) w[i] = ~x.words[i]; break; + } + result.ival = i; + } + + /** Return the logical (bit-wise) "and" of a BigInteger and an int. */ + private static BigInteger and(BigInteger x, int y) + { + if (x.words == null) + return valueOf(x.ival & y); + if (y >= 0) + return valueOf(x.words[0] & y); + int len = x.ival; + int[] words = new int[len]; + words[0] = x.words[0] & y; + while (--len > 0) + words[len] = x.words[len]; + return make(words, x.ival); + } + + /** Return the logical (bit-wise) "and" of two BigIntegers. */ + public BigInteger and(BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.and(y.mpz, result.mpz); + return result; + }*/ + + if (y.words == null) + return and(this, y.ival); + else if (words == null) + return and(y, ival); + + BigInteger x = this; + if (ival < y.ival) + { + BigInteger temp = this; x = y; y = temp; + } + int i; + int len = y.isNegative() ? x.ival : y.ival; + int[] words = new int[len]; + for (i = 0; i < y.ival; i++) + words[i] = x.words[i] & y.words[i]; + for ( ; i < len; i++) + words[i] = x.words[i]; + return make(words, len); + } + + /** Return the logical (bit-wise) "(inclusive) or" of two BigIntegers. */ + public BigInteger or(BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.or(y.mpz, result.mpz); + return result; + }*/ + + return bitOp(7, this, y); + } + + /** Return the logical (bit-wise) "exclusive or" of two BigIntegers. */ + public BigInteger xor(BigInteger y) + { + /*if (USING_NATIVE) + { + int dummy = y.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.xor(y.mpz, result.mpz); + return result; + }*/ + + return bitOp(6, this, y); + } + + /** Return the logical (bit-wise) negation of a BigInteger. */ + public BigInteger not() + { + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.not(result.mpz); + return result; + }*/ + + return bitOp(12, this, ZERO); + } + + public BigInteger andNot(BigInteger val) + { + /*if (USING_NATIVE) + { + int dummy = val.signum; // force NPE check + BigInteger result = new BigInteger(); + mpz.andNot(val.mpz, result.mpz); + return result; + }*/ + + return and(val.not()); + } + + public BigInteger clearBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.setBit(n, false, result.mpz); + return result; + }*/ + + return and(ONE.shiftLeft(n).not()); + } + + public BigInteger setBit(int n) + { + if (n < 0) + throw new ArithmeticException(); + + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.setBit(n, true, result.mpz); + return result; + }*/ + + return or(ONE.shiftLeft(n)); + } + + public boolean testBit(int n) + { + if (n < 0) + throw new Error("Arithmetic Exception")/*ArithmeticException()*/; + + /*if (USING_NATIVE) + return mpz.testBit(n) != 0;*/ + + return !and(ONE.shiftLeft(n)).isZero(); + } + + public BigInteger flipBit(int n) + { + if (n < 0) + throw new Error("Arithmetic Exception")/*ArithmeticException()*/; + + /*if (USING_NATIVE) + { + BigInteger result = new BigInteger(); + mpz.flipBit(n, result.mpz); + return result; + }*/ + + return xor(ONE.shiftLeft(n)); + } + + public int getLowestSetBit() + { + /*if (USING_NATIVE) + return mpz.compare(ZERO.mpz) == 0 ? -1 : mpz.lowestSetBit();*/ + + if (isZero()) + return -1; + + if (words == null) + return MPN.findLowestBit(ival); + else + return MPN.findLowestBit(words); + } + + // bit4count[I] is number of '1' bits in I. + private static final byte[] bit4_count = { 0, 1, 1, 2, 1, 2, 2, 3, + 1, 2, 2, 3, 2, 3, 3, 4}; + + private static int bitCount(int i) + { + int count = 0; + while (i != 0) + { + count += bit4_count[i & 15]; + i >>>= 4; + } + return count; + } + + private static int bitCount(int[] x, int len) + { + int count = 0; + while (--len >= 0) + count += bitCount(x[len]); + return count; + } + + /** Count one bits in a BigInteger. + * If argument is negative, count zero bits instead. */ + public int bitCount() + { + /*if (USING_NATIVE) + return mpz.bitCount();*/ + + int i, x_len; + int[] x_words = words; + if (x_words == null) + { + x_len = 1; + i = bitCount(ival); + } + else + { + x_len = ival; + i = bitCount(x_words, x_len); + } + return isNegative() ? x_len * 32 - i : i; + } + + /*private void readObject(ObjectInputStream s) + //throws IOException, ClassNotFoundException + { + if (USING_NATIVE) + { + mpz = new GMP(); + s.defaultReadObject(); + if (signum != 0) + mpz.fromByteArray(magnitude); + // else it's zero and we need to do nothing + } + else + { + s.defaultReadObject(); + if (magnitude.length == 0 || signum == 0) + { + this.ival = 0; + this.words = null; + } + else + { + words = byteArrayToIntArray(magnitude, signum < 0 ? -1 : 0); + BigInteger result = make(words, words.length); + this.ival = result.ival; + this.words = result.words; + } + } + }*/ + + /*private void writeObject(ObjectOutputStream s) + //throws IOException, ClassNotFoundException + { + signum = signum(); + magnitude = signum == 0 ? new byte[0] : toByteArray(); + s.defaultWriteObject(); + magnitude = null; // not needed anymore + }*/ + + // inner class(es) .......................................................... + +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/BufferedReader.java b/Robust/src/ClassLibrary/MGC/gnu/BufferedReader.java new file mode 100644 index 00000000..f91bc4c8 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/BufferedReader.java @@ -0,0 +1,576 @@ +/* BufferedReader.java + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.io; + +//import gnu.java.lang.CPStringBuilder; + +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This subclass of FilterReader buffers input from an + * underlying implementation to provide a possibly more efficient read + * mechanism. It maintains the buffer and buffer state in instance + * variables that are available to subclasses. The default buffer size + * of 8192 chars can be overridden by the creator of the stream. + *

+ * This class also implements mark/reset functionality. It is capable + * of remembering any number of input chars, to the limits of + * system memory or the size of Integer.MAX_VALUE + * + * @author Per Bothner (bothner@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public class BufferedReader extends Reader +{ + Reader in; + char[] buffer; + /* Index of current read position. Must be >= 0 and <= limit. */ + /* There is a special case where pos may be equal to limit+1; this + * is used as an indicator that a readLine was done with a '\r' was + * the very last char in the buffer. Since we don't want to read-ahead + * and potentially block, we set pos this way to indicate the situation + * and deal with it later. Doing it this way rather than having a + * separate boolean field to indicate the condition has the advantage + * that it is self-clearing on things like mark/reset. + */ + int pos; + /* Limit of valid data in buffer. Must be >= pos and <= buffer.length. */ + /* This can be < pos in the one special case described above. */ + int limit; + + /* The value -1 means there is no mark, or the mark has been invalidated. + Otherwise, markPos is the index in the buffer of the marked position. + Must be >= 0 and <= pos. + Note we do not explicitly store the read-limit. + The implicit read-limit is (buffer.length - markPos), which is + guaranteed to be >= the read-limit requested in the call to mark. */ + int markPos = -1; + + // The JCL book specifies the default buffer size as 8K characters. + // This is package-private because it is used by LineNumberReader. + static final int DEFAULT_BUFFER_SIZE = 8192; + + /** + * Create a new BufferedReader that will read from the + * specified subordinate stream with a default buffer size of 8192 chars. + * + * @param in The subordinate stream to read from + */ + public BufferedReader(Reader in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + /** + * Create a new BufferedReader that will read from the + * specified subordinate stream with a buffer size that is specified by the + * caller. + * + * @param in The subordinate stream to read from + * @param size The buffer size to use + * + * @exception IllegalArgumentException if size <= 0 + */ + public BufferedReader(Reader in, int size) + { + super(in.lock); + if (size <= 0) + throw new Error/*IllegalArgumentException*/("IllegalArgumentException Illegal buffer size: " + size); + this.in = in; + buffer = new char[size]; + } + + /** + * This method closes the underlying stream and frees any associated + * resources. + * + * @exception IOException If an error occurs + */ + public void close() //throws IOException + { + synchronized (lock) + { + if (in != null) + in.close(); + in = null; + buffer = null; + } + } + + /** + * Returns true to indicate that this class supports mark/reset + * functionality. + * + * @return true + */ + public boolean markSupported() + { + return true; + } + + /** + * Mark a position in the input to which the stream can be + * "reset" by calling the reset() method. The parameter + * readLimit is the number of chars that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if mark() is called with a read limit of 10, then + * when 11 chars of data are read from the stream before the + * reset() method is called, then the mark is invalid and the + * stream object instance is not required to remember the mark. + *

+ * Note that the number of chars that can be remembered by this method + * can be greater than the size of the internal read buffer. It is also + * not dependent on the subordinate stream supporting mark/reset + * functionality. + * + * @param readLimit The number of chars that can be read before the mark + * becomes invalid + * + * @exception IOException If an error occurs + * @exception IllegalArgumentException if readLimit is negative. + */ + public void mark(int readLimit) //throws IOException + { + if (readLimit < 0) + throw new Error/*IllegalArgumentException*/("IllegalArgumentException Read-ahead limit is negative"); + + synchronized (lock) + { + checkStatus(); + // In this method we need to be aware of the special case where + // pos + 1 == limit. This indicates that a '\r' was the last char + // in the buffer during a readLine. We'll want to maintain that + // condition after we shift things around and if a larger buffer is + // needed to track readLimit, we'll have to make it one element + // larger to ensure we don't invalidate the mark too early, if the + // char following the '\r' is NOT a '\n'. This is ok because, per + // the spec, we are not required to invalidate when passing readLimit. + // + // Note that if 'pos > limit', then doing 'limit -= pos' will cause + // limit to be negative. This is the only way limit will be < 0. + + if (pos + readLimit > limit) + { + char[] old_buffer = buffer; + int extraBuffSpace = 0; + if (pos > limit) + extraBuffSpace = 1; + if (readLimit + extraBuffSpace > limit) + buffer = new char[readLimit + extraBuffSpace]; + limit -= pos; + if (limit >= 0) + { + System.arraycopy(old_buffer, pos, buffer, 0, limit); + pos = 0; + } + } + + if (limit < 0) + { + // Maintain the relationship of 'pos > limit'. + pos = 1; + limit = markPos = 0; + } + else + markPos = pos; + // Now pos + readLimit <= buffer.length. thus if we need to read + // beyond buffer.length, then we are allowed to invalidate markPos. + } + } + + /** + * Reset the stream to the point where the mark() method + * was called. Any chars that were read after the mark point was set will + * be re-read during subsequent reads. + *

+ * This method will throw an IOException if the number of chars read from + * the stream since the call to mark() exceeds the mark limit + * passed when establishing the mark. + * + * @exception IOException If an error occurs; + */ + public void reset() //throws IOException + { + synchronized (lock) + { + checkStatus(); + if (markPos < 0) + throw new Error/*IOException*/("mark never set or invalidated"); + + // Need to handle the extremely unlikely case where a readLine was + // done with a '\r' as the last char in the buffer; which was then + // immediately followed by a mark and a reset with NO intervening + // read of any sort. In that case, setting pos to markPos would + // lose that info and a subsequent read would thus not skip a '\n' + // (if one exists). The value of limit in this rare case is zero. + // We can assume that if limit is zero for other reasons, then + // pos is already set to zero and doesn't need to be readjusted. + if (limit > 0) + pos = markPos; + } + } + + /** + * This method determines whether or not a stream is ready to be read. If + * this method returns false then this stream could (but is + * not guaranteed to) block on the next read attempt. + * + * @return true if this stream is ready to be read, + * false otherwise + * + * @exception IOException If an error occurs + */ + public boolean ready() //throws IOException + { + synchronized (lock) + { + checkStatus(); + return pos < limit || in.ready(); + } + } + + /** + * This method read chars from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index + * offset into + * the buffer and attempts to read len chars. This method can + * return before reading the number of chars requested. The actual number + * of chars read is returned as an int. A -1 is returned to indicate the + * end of the stream. + *

+ * This method will block until some data can be read. + * + * @param buf The array into which the chars read should be stored + * @param offset The offset into the array to start storing chars + * @param count The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + * @exception IndexOutOfBoundsException If offset and count are not + * valid regarding buf. + */ + public int read(char[] buf, int offset, int count) //throws IOException + { + if (offset < 0 || offset + count > buf.length || count < 0) + throw new Error/*IndexOutOfBoundsException*/("IndexOutOfBoundsException"); + + synchronized (lock) + { + checkStatus(); + // Once again, we need to handle the special case of a readLine + // that has a '\r' at the end of the buffer. In this case, we'll + // need to skip a '\n' if it is the next char to be read. + // This special case is indicated by 'pos > limit'. + boolean retAtEndOfBuffer = false; + + int avail = limit - pos; + if (count > avail) + { + if (avail > 0) + count = avail; + else // pos >= limit + { + if (limit == buffer.length) + markPos = -1; // read too far - invalidate the mark. + if (pos > limit) + { + // Set a boolean and make pos == limit to simplify things. + retAtEndOfBuffer = true; + --pos; + } + if (markPos < 0) + { + // Optimization: can read directly into buf. + if (count >= buffer.length && !retAtEndOfBuffer) + return in.read(buf, offset, count); + pos = limit = 0; + } + avail = in.read(buffer, limit, buffer.length - limit); + if (retAtEndOfBuffer && avail > 0 && buffer[limit] == '\n') + { + --avail; + limit++; + } + if (avail < count) + { + if (avail <= 0) + return avail; + count = avail; + } + limit += avail; + } + } + System.arraycopy(buffer, pos, buf, offset, count); + pos += count; + return count; + } + } + + /* Read more data into the buffer. Update pos and limit appropriately. + Assumes pos==limit initially. May invalidate the mark if read too much. + Return number of chars read (never 0), or -1 on eof. */ + private int fill() //throws IOException + { + checkStatus(); + // Handle the special case of a readLine that has a '\r' at the end of + // the buffer. In this case, we'll need to skip a '\n' if it is the + // next char to be read. This special case is indicated by 'pos > limit'. + boolean retAtEndOfBuffer = false; + if (pos > limit) + { + retAtEndOfBuffer = true; + --pos; + } + + if (markPos >= 0 && limit == buffer.length) + markPos = -1; + if (markPos < 0) + pos = limit = 0; + int count = in.read(buffer, limit, buffer.length - limit); + if (count > 0) + limit += count; + + if (retAtEndOfBuffer && buffer[pos] == '\n') + { + --count; + // If the mark was set to the location of the \n, then we + // must change it to fully pretend that the \n does not + // exist. + if (markPos == pos) + ++markPos; + ++pos; + } + + return count; + } + + public int read() //throws IOException + { + synchronized (lock) + { + checkStatus(); + if (pos >= limit && fill () <= 0) + return -1; + return buffer[pos++]; + } + } + + /* Return the end of the line starting at this.pos and ending at limit. + * The index returns is *before* any line terminators, or limit + * if no line terminators were found. + */ + private int lineEnd(int limit) + { + int i = pos; + for (; i < limit; i++) + { + char ch = buffer[i]; + if (ch == '\n' || ch == '\r') + break; + } + return i; + } + + /** + * This method reads a single line of text from the input stream, returning + * it as a String. A line is terminated by "\n", a "\r", or + * an "\r\n" sequence. The system dependent line separator is not used. + * The line termination characters are not returned in the resulting + * String. + * + * @return The line of text read, or null if end of stream. + * + * @exception IOException If an error occurs + */ + public String readLine() //throws IOException + {/* + checkStatus(); + // Handle the special case where a previous readLine (with no intervening + // reads/skips) had a '\r' at the end of the buffer. + // In this case, we'll need to skip a '\n' if it's the next char to be read. + // This special case is indicated by 'pos > limit'. + if (pos > limit) + { + int ch = read(); + if (ch < 0) + return null; + if (ch != '\n') + --pos; + } + int i = lineEnd(limit); + if (i < limit) + { + String str = String.valueOf(buffer, pos, i - pos); + pos = i + 1; + // If the last char in the buffer is a '\r', we must remember + // to check if the next char to be read after the buffer is refilled + // is a '\n'. If so, skip it. To indicate this condition, we set pos + // to be limit + 1, which normally is never possible. + if (buffer[i] == '\r') + if (pos == limit || buffer[pos] == '\n') + pos++; + return str; + } + CPStringBuilder sbuf = new CPStringBuilder(200); + sbuf.append(buffer, pos, i - pos); + pos = i; + // We only want to return null when no characters were read before + // EOF. So we must keep track of this separately. Otherwise we + // would treat an empty `sbuf' as an EOF condition, which is wrong + // when there is just a newline. + boolean eof = false; + for (;;) + { + // readLine should block. So we must not return until a -1 is reached. + if (pos >= limit) + { + // here count == 0 isn't sufficient to give a failure. + int count = fill(); + if (count < 0) + { + eof = true; + break; + } + continue; + } + int ch = buffer[pos++]; + if (ch == '\n' || ch == '\r') + { + // Check here if a '\r' was the last char in the buffer; if so, + // mark it as in the comment above to indicate future reads + // should skip a newline that is the next char read after + // refilling the buffer. + if (ch == '\r') + if (pos == limit || buffer[pos] == '\n') + pos++; + break; + } + i = lineEnd(limit); + sbuf.append(buffer, pos - 1, i - (pos - 1)); + pos = i; + } + return (sbuf.length() == 0 && eof) ? null : sbuf.toString();*/ + return null; + } + + /** + * This method skips the specified number of chars in the stream. It + * returns the actual number of chars skipped, which may be less than the + * requested amount. + *

+ * This method first discards chars in the buffer, then calls the + * skip method on the underlying stream to skip the + * remaining chars. + * + * @param count The requested number of chars to skip + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs. + * @exception IllegalArgumentException If count is negative. + */ + public long skip(long count) //throws IOException + { + synchronized (lock) + { + checkStatus(); + if (count < 0) + throw new Error/*IllegalArgumentException*/("skip value is negative"); + if (count == 0) + return 0; + // Yet again, we need to handle the special case of a readLine + // that has a '\r' at the end of the buffer. In this case, we need + // to ignore a '\n' if it is the next char to be read. + // This special case is indicated by 'pos > limit' (i.e. avail < 0). + // To simplify things, if we're dealing with the special case for + // readLine, just read the next char (since the fill method will + // skip the '\n' for us). By doing this, we'll have to back up pos. + // That's easier than trying to keep track of whether we've skipped + // one element or not. + if (pos > limit) + { + if (read() < 0) + return 0; + else + --pos; + } + + int avail = limit - pos; + + if (count < avail) + { + pos += count; + return count; + } + + pos = limit; + long todo = count - avail; + if (todo > buffer.length) + { + markPos = -1; + todo -= in.skip(todo); + } + else + { + while (todo > 0) + { + avail = fill(); + if (avail <= 0) + break; + if (avail > todo) + avail = (int) todo; + pos += avail; + todo -= avail; + } + } + return count - todo; + } + } + + private void checkStatus() //throws IOException + { + if (in == null) + throw new Error/*IOException*/("Stream closed"); + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/Calendar.java b/Robust/src/ClassLibrary/MGC/gnu/Calendar.java new file mode 100644 index 00000000..7dc6cf23 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Calendar.java @@ -0,0 +1,1621 @@ +/* Calendar.java -- + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006, + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/*import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import java.text.DateFormatSymbols;*/ + +/** + * This class is an abstract base class for Calendars, which can be + * used to convert between Date objects and a set of + * integer fields which represent YEAR, + * MONTH, DAY, etc. The Date + * object represents a time in milliseconds since the Epoch.
+ * + * This class is locale sensitive. To get the Object matching the + * current locale you can use getInstance. You can even provide + * a locale or a timezone. getInstance returns currently + * a GregorianCalendar for the current date.
+ * + * If you want to convert a date from the Year, Month, Day, DayOfWeek, + * etc. Representation to a Date-Object, you can create + * a new Calendar with getInstance(), + * clear() all fields, set(int,int) the + * fields you need and convert it with getTime().
+ * + * If you want to convert a Date-object to the Calendar + * representation, create a new Calendar, assign the + * Date-Object with setTime(), and read the + * fields with get(int).
+ * + * When computing the date from time fields, it may happen, that there + * are either two few fields set, or some fields are inconsistent. This + * cases will handled in a calendar specific way. Missing fields are + * replaced by the fields of the epoch: 1970 January 1 00:00.
+ * + * To understand, how the day of year is computed out of the fields + * look at the following table. It is traversed from top to bottom, + * and for the first line all fields are set, that line is used to + * compute the day.
+ * + * +

month + day_of_month
+month + week_of_month + day_of_week
+month + day_of_week_of_month + day_of_week
+day_of_year
+day_of_week + week_of_year
+ * + * The hour_of_day-field takes precedence over the ampm and + * hour_of_ampm fields.
+ * + * Note: This can differ for non-Gregorian calendar.
+ * + * To convert a calendar to a human readable form and vice versa, use + * the java.text.DateFormat class.
+ * + * Other useful things you can do with an calendar, is + * rolling fields (that means increase/decrease a + * specific field by one, propagating overflows), or + * adding/substracting a fixed amount to a field. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Jochen Hoenicke (Jochen.Hoenicke@Informatik.Uni-Oldenburg.de) + * @author Warren Levy (warrenl@cygnus.com) + * @author Jeff Sturm (jsturm@one-point.com) + * @author Tom Tromey (tromey@redhat.com) + * @author Bryce McKinlay (mckinlay@redhat.com) + * @author Ingo Proetel (proetel@aicas.com) + * @author Jerry Quinn (jlquinn@optonline.net) + * @author Jeroen Frijters (jeroen@frijters.net) + * @author Noa Resare (noa@resare.com) + * @author Sven de Marothy (sven@physto.se) + * @author David Gilbert (david.gilbert@object-refinery.com) + * @author Olivier Jolly (olivier.jolly@pcedev.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @see Date + * @see GregorianCalendar + * @see TimeZone + * @see java.text.DateFormat + */ +public /*abstract*/ class Calendar + //implements Serializable, Cloneable, Comparable +{ + /** + * Constant representing the era time field. + */ + public static final int ERA = 0; + + /** + * Constant representing the year time field. + */ + public static final int YEAR = 1; + + /** + * Constant representing the month time field. This field + * should contain one of the JANUARY,...,DECEMBER constants below. + */ + public static final int MONTH = 2; + + /** + * Constant representing the week of the year field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_YEAR = 3; + + /** + * Constant representing the week of the month time field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_MONTH = 4; + + /** + * Constant representing the day time field, synonym for DAY_OF_MONTH. + */ + public static final int DATE = 5; + + /** + * Constant representing the day time field. + */ + public static final int DAY_OF_MONTH = 5; + + /** + * Constant representing the day of year time field. This is + * 1 for the first day in month. + */ + public static final int DAY_OF_YEAR = 6; + + /** + * Constant representing the day of week time field. This field + * should contain one of the SUNDAY,...,SATURDAY constants below. + */ + public static final int DAY_OF_WEEK = 7; + + /** + * Constant representing the day-of-week-in-month field. For + * instance this field contains 2 for the second thursday in a + * month. If you give a negative number here, the day will count + * from the end of the month. + */ + public static final int DAY_OF_WEEK_IN_MONTH = 8; + + /** + * Constant representing the part of the day for 12-hour clock. This + * should be one of AM or PM. + */ + public static final int AM_PM = 9; + + /** + * Constant representing the hour time field for 12-hour clock. + */ + public static final int HOUR = 10; + + /** + * Constant representing the hour of day time field for 24-hour clock. + */ + public static final int HOUR_OF_DAY = 11; + + /** + * Constant representing the minute of hour time field. + */ + public static final int MINUTE = 12; + + /** + * Constant representing the second time field. + */ + public static final int SECOND = 13; + + /** + * Constant representing the millisecond time field. + */ + public static final int MILLISECOND = 14; + + /** + * Constant representing the time zone offset time field for the + * time given in the other fields. It is measured in + * milliseconds. The default is the offset of the time zone. + */ + public static final int ZONE_OFFSET = 15; + + /** + * Constant representing the daylight saving time offset in + * milliseconds. The default is the value given by the time zone. + */ + public static final int DST_OFFSET = 16; + + /** + * Number of time fields. + */ + public static final int FIELD_COUNT = 17; + + /** + * Constant representing Sunday. + */ + public static final int SUNDAY = 1; + + /** + * Constant representing Monday. + */ + public static final int MONDAY = 2; + + /** + * Constant representing Tuesday. + */ + public static final int TUESDAY = 3; + + /** + * Constant representing Wednesday. + */ + public static final int WEDNESDAY = 4; + + /** + * Constant representing Thursday. + */ + public static final int THURSDAY = 5; + + /** + * Constant representing Friday. + */ + public static final int FRIDAY = 6; + + /** + * Constant representing Saturday. + */ + public static final int SATURDAY = 7; + + /** + * Constant representing January. + */ + public static final int JANUARY = 0; + + /** + * Constant representing February. + */ + public static final int FEBRUARY = 1; + + /** + * Constant representing March. + */ + public static final int MARCH = 2; + + /** + * Constant representing April. + */ + public static final int APRIL = 3; + + /** + * Constant representing May. + */ + public static final int MAY = 4; + + /** + * Constant representing June. + */ + public static final int JUNE = 5; + + /** + * Constant representing July. + */ + public static final int JULY = 6; + + /** + * Constant representing August. + */ + public static final int AUGUST = 7; + + /** + * Constant representing September. + */ + public static final int SEPTEMBER = 8; + + /** + * Constant representing October. + */ + public static final int OCTOBER = 9; + + /** + * Constant representing November. + */ + public static final int NOVEMBER = 10; + + /** + * Constant representing December. + */ + public static final int DECEMBER = 11; + + /** + * Constant representing Undecimber. This is an artificial name useful + * for lunar calendars. + */ + public static final int UNDECIMBER = 12; + + /** + * Useful constant for 12-hour clock. + */ + public static final int AM = 0; + + /** + * Useful constant for 12-hour clock. + */ + public static final int PM = 1; + + /** + * A style specifier for {@link #getDisplayNames(int,int,Locale)} + * stating that names should be returned in both long and short variants. + * + * @since 1.6 + * @see #SHORT + * @see #LONG + */ + public static final int ALL_STYLES = 0; + + /** + * A style specifier for {@link #getDisplayName(int,int,Locale)} + * and {@link #getDisplayNames(int,int,Locale)} stating that names + * should be returned in their short variant if applicable. + * + * @since 1.6 + */ + public static final int SHORT = 1; + + /** + * A style specifier for {@link #getDisplayName(int,int,Locale)} + * and {@link #getDisplayNames(int,int,Locale)} stating that names + * should be returned in their long variant if applicable. + * + * @since 1.6 + */ + public static final int LONG = 2; + + /** + * The time fields. The array is indexed by the constants YEAR to + * DST_OFFSET. + * @serial + */ + protected int[] fields = new int[FIELD_COUNT]; + + /** + * The flags which tell if the fields above have a value. + * @serial + */ + protected boolean[] isSet = new boolean[FIELD_COUNT]; + + /** + * The time in milliseconds since the epoch. + * @serial + */ + protected long time; + + /** + * Tells if the above field has a valid value. + * @serial + */ + protected boolean isTimeSet; + + /** + * Tells if the fields have a valid value. This superseeds the isSet + * array. + * @serial + */ + protected boolean areFieldsSet; + + /** + * The time zone of this calendar. Used by sub classes to do UTC / local + * time conversion. Sub classes can access this field with getTimeZone(). + * @serial + */ + private TimeZone zone; + + /** + * This is the default calendar class, that is returned on + * java.util.Calendar.getInstance(). + * XXX - this isn't localized anywhere, is it? + * @see java.util.Calendar#getInstance() + */ + private static final String calendarClassName = "java.util.GregorianCalendar"; + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @serial + */ + private boolean lenient; + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @serial + */ + private int firstDayOfWeek; + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @serial + */ + private int minimalDaysInFirstWeek; + + /** + * Is set to true if DST_OFFSET is explicitly set. In that case + * it's value overrides the value computed from the current + * time and the timezone. + */ + private boolean explicitDSTOffset = false; + + /** + * The version of the serialized data on the stream. + *
0 or not present
+ *
JDK 1.1.5 or later.
+ *
1
+ *
JDK 1.1.6 or later. This always writes a correct `time' value + * on the stream, as well as the other fields, to be compatible with + * earlier versions
+ * @since JDK1.1.6 + * @serial + */ + private int serialVersionOnStream = 1; + + /** + * XXX - I have not checked the compatibility. The documentation of + * the serialized-form is quite hairy... + */ + static final long serialVersionUID = -1807547505821590642L; + + /** + * The name of the resource bundle. Used only by getBundle() + */ + private static final String bundleName = "gnu.java.locale.LocaleInformation"; + + /** + * get resource bundle: + * The resources should be loaded via this method only. Iff an application + * uses this method, the resourcebundle is required. + */ + /*private static ResourceBundle getBundle(Locale locale) + { + return ResourceBundle.getBundle(bundleName, locale, + ClassLoader.getSystemClassLoader()); + }*/ + + /** + * The set of properties for obtaining the minimum number of days in + * the first week. + */ + //private static transient final Properties properties; + + /** + * Reads in the properties. + */ + /*static + { + properties = new Properties(); + try + { + properties.load(Calendar.class.getResourceAsStream("weeks.properties")); + } + catch (IOException exception) + { + System.out.println("Failed to load weeks resource: " + exception); + } + }*/ + + /** + * Constructs a new Calendar with the default time zone and the default + * locale. + */ + protected Calendar() + { + this(/*TimeZone.getDefault(), */Locale.getDefault()); + } + + /** + * Constructs a new Calendar with the given time zone and the given + * locale. + * @param zone a time zone. + * @param locale a locale. + */ + protected Calendar(/*TimeZone zone, */Locale locale) + { + //this.zone = zone; + lenient = true; + String[] days = { "", "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; + + /*String country = locale.getCountry(); + String min = properties.getProperty("minDays." + country); + if (min == null) + min = properties.getProperty("minDays.DEFAULT"); + String first = properties.getProperty("firstDay." + country); + if (first == null) + first = properties.getProperty("firstDay.DEFAULT"); + try + { + if (min != null) + minimalDaysInFirstWeek = Integer.parseInt(min); + } + catch (NumberFormatException ex) + { + minimalDaysInFirstWeek = 1; + }*/ + + firstDayOfWeek = 1; + /*if (first != null) + for (int i = 0; i < 8; i++) + if (days[i].equals(first)) + firstDayOfWeek = i;*/ + + clear(); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and locale. + * + * @return The new calendar. + */ + public static synchronized Calendar getInstance() + { + return getInstance(/*TimeZone.getDefault(), */Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the given + * time zone and the default locale. + * + * @param zone a time zone (null not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if zone is null. + */ + /*public static synchronized Calendar getInstance(TimeZone zone) + { + return getInstance(zone, Locale.getDefault()); + }*/ + + /** + * Creates a calendar representing the actual time, using the default + * time zone and the given locale. + * + * @param locale a locale (null not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if locale is null. + */ + /*public static synchronized Calendar getInstance(Locale locale) + { + return getInstance(TimeZone.getDefault(), locale); + }*/ + + /** + * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle + * lookup for every getInstance call. + */ + private static final HashMap/**/ cache = new HashMap/**/(); + + /** Preset argument types for calendar-class constructor lookup. */ + /*private static Class[] ctorArgTypes = new Class[] + { + TimeZone.class, Locale.class + };*/ + + /** + * Creates a calendar representing the actual time, using the given + * time zone and locale. + * + * @param zone a time zone (null not permitted). + * @param locale a locale (null not permitted). + * + * @return The new calendar. + * + * @throws NullPointerException if zone or locale + * is null. + */ + public static synchronized Calendar getInstance(/*TimeZone zone, */Locale locale) + { + Class calendarClass = (Class)cache.get(locale); + //Throwable exception = null; + + /*try + { + if (calendarClass == null) + { + calendarClass = Class.forName(calendarClassName); + if (Calendar.class.isAssignableFrom(calendarClass)) + cache.put(locale, calendarClass); + }*/ + + // GregorianCalendar is by far the most common case. Optimize by + // avoiding reflection. + //if (calendarClass == GregorianCalendar.class) + return new GregorianCalendar(zone, locale); + + /*if (Calendar.class.isAssignableFrom(calendarClass)) + { + Constructor ctor = calendarClass.getConstructor(ctorArgTypes); + return (Calendar) ctor.newInstance(new Object[] { zone, locale }); + } + } + catch (ClassNotFoundException ex) + { + exception = ex; + } + catch (IllegalAccessException ex) + { + exception = ex; + } + catch (NoSuchMethodException ex) + { + exception = ex; + } + catch (InstantiationException ex) + { + exception = ex; + } + catch (InvocationTargetException ex) + { + exception = ex; + } + + throw new RuntimeException("Error instantiating calendar for locale " + + locale, exception);*/ + } + + /** + * Gets the set of locales for which a Calendar is available. + * @exception MissingResourceException if locale data couldn't be found. + * @return the set of locales. + */ + /*public static synchronized Locale[] getAvailableLocales() + { + ResourceBundle rb = getBundle(new Locale("", "")); + return (Locale[]) rb.getObject("availableLocales"); + }*/ + + /** + * Converts the time field values (fields) to + * milliseconds since the epoch UTC (time). Override + * this method if you write your own Calendar. */ + protected /*abstract*/ void computeTime(); + + /** + * Converts the milliseconds since the epoch UTC + * (time) to time fields + * (fields). Override this method if you write your + * own Calendar. + */ + protected /*abstract*/ void computeFields(); + + /** + * Converts the time represented by this object to a + * Date-Object. + * @return the Date. + */ + /*public final Date getTime() + { + if (! isTimeSet) + computeTime(); + return new Date(time); + }*/ + + /** + * Sets this Calendar's time to the given Date. All time fields + * are invalidated by this method. + * + * @param date the date (null not permitted). + * + * @throws NullPointerException if date is null. + */ + public final void setTime(Date date) + { + setTimeInMillis(date.getTime()); + } + + /** + * Returns the time represented by this Calendar. + * @return the time in milliseconds since the epoch. + * @specnote This was made public in 1.4. + */ + /*public long getTimeInMillis() + { + if (! isTimeSet) + computeTime(); + return time; + }*/ + + /** + * Sets this Calendar's time to the given Time. All time fields + * are invalidated by this method. + * @param time the time in milliseconds since the epoch + * @specnote This was made public in 1.4. + */ + public void setTimeInMillis(long time) + { + clear(); + this.time = time; + isTimeSet = true; + computeFields(); + } + + /** + * Gets the value of the specified field. They are recomputed + * if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @specnote Not final since JDK 1.4 + */ + public int get(int field) + { + // If the requested field is invalid, force all fields to be recomputed. + if (! isSet[field]) + areFieldsSet = false; + complete(); + return fields[field]; + } + + /** + * Gets the value of the specified field. This method doesn't + * recompute the fields, if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field, undefined if + * areFieldsSet or isSet[field] is false. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + protected final int internalGet(int field) + { + return fields[field]; + } + + /** + * Sets the time field with the given value. This does invalidate + * the time in milliseconds. + * @param field the time field. One of the time field constants + * @param value the value to be set. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @specnote Not final since JDK 1.4 + */ + /*public void set(int field, int value) + { + if (isTimeSet) + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + isTimeSet = false; + fields[field] = value; + isSet[field] = true; + + // The five valid date patterns, in order of priority + // 1 YEAR + MONTH + DAY_OF_MONTH + // 2 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + // 3 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + // 4 YEAR + DAY_OF_YEAR + // 5 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + switch (field) + { + case MONTH: // pattern 1,2 or 3 + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: // pattern 1 + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[WEEK_OF_MONTH] = true; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case WEEK_OF_MONTH: // pattern 2 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_WEEK_IN_MONTH: // pattern 3 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_YEAR: // pattern 4 + isSet[YEAR] = true; + isSet[MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case WEEK_OF_YEAR: // pattern 5 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[DAY_OF_WEEK] = true; + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case AM_PM: + isSet[HOUR] = true; + isSet[HOUR_OF_DAY] = false; + break; + case HOUR_OF_DAY: + isSet[AM_PM] = false; + isSet[HOUR] = false; + break; + case HOUR: + isSet[AM_PM] = true; + isSet[HOUR_OF_DAY] = false; + break; + case DST_OFFSET: + explicitDSTOffset = true; + } + + // May have crossed over a DST boundary. + if (! explicitDSTOffset && (field != DST_OFFSET && field != ZONE_OFFSET)) + isSet[DST_OFFSET] = false; + }*/ + + /** + * Sets the fields for year, month, and date + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + */ + /*public final void set(int year, int month, int date) + { + isTimeSet = false; + fields[YEAR] = year; + fields[MONTH] = month; + fields[DATE] = date; + isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[ERA] = false; + + if (! explicitDSTOffset) + isSet[DST_OFFSET] = false; // May have crossed a DST boundary. + }*/ + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + */ + /*public final void set(int year, int month, int date, int hour, int minute) + { + set(year, month, date); + fields[HOUR_OF_DAY] = hour; + fields[MINUTE] = minute; + isSet[HOUR_OF_DAY] = isSet[MINUTE] = true; + isSet[AM_PM] = false; + isSet[HOUR] = false; + }*/ + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + * @param second the second. + */ + /*public final void set(int year, int month, int date, int hour, int minute, + int second) + { + set(year, month, date, hour, minute); + fields[SECOND] = second; + isSet[SECOND] = true; + }*/ + + /** + * Clears the values of all the time fields. + */ + public final void clear() + { + isTimeSet = false; + areFieldsSet = false; + int zoneOffs = 0;//zone.getRawOffset(); + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zoneOffs, 0 + }; + fields = tempFields; + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + } + + /** + * Clears the values of the specified time field. + * @param field the time field. One of the time field constants. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public final void clear(int field) + { + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, 0/*zone.getRawOffset()*/, 0 + }; + complete(); + isTimeSet = false; + areFieldsSet = false; + isSet[field] = false; + fields[field] = tempFields[field]; + } + + /** + * Determines if the specified field has a valid value. + * @return true if the specified field has a value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public final boolean isSet(int field) + { + return isSet[field]; + } + + /** + * Fills any unset fields in the time field list + */ + protected void complete() + { + if (! isTimeSet) + computeTime(); + if (! areFieldsSet) + computeFields(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessary have the same fields). + */ + // TODO always false now + public boolean equals(Object o) + { + if (! (o instanceof Calendar)) + return false; + Calendar cal = (Calendar) o; + /*if (getTimeInMillis() == ((Calendar) o).getTimeInMillis() + && cal.getFirstDayOfWeek() == getFirstDayOfWeek() + && cal.isLenient() == isLenient() + && cal.getMinimalDaysInFirstWeek() == getMinimalDaysInFirstWeek()) + { + TimeZone self = getTimeZone(); + TimeZone oth = cal.getTimeZone(); + return self == null ? oth == null : self.equals(oth); + }*/ + return false; + } + + /** + * Returns a hash code for this calendar. + * @return a hash code, which fullfits the general contract of + * hashCode() + */ + public int hashCode() + { + long time = getTimeInMillis(); + int val = (int) ((time & 0xffffffffL) ^ (time >> 32)); + /*val += (getFirstDayOfWeek() + (isLenient() ? 1230 : 1237) + + getMinimalDaysInFirstWeek()); + TimeZone self = getTimeZone(); + if (self != null) + val ^= self.hashCode();*/ + return val; + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a smaller time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + /*public boolean before(Object o) + { + return getTimeInMillis() < ((Calendar) o).getTimeInMillis(); + }*/ + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a bigger time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + /*public boolean after(Object o) + { + return getTimeInMillis() > ((Calendar) o).getTimeInMillis(); + }*/ + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field the time field. One of the time field constants. + * @param amount the amount of time. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public /*abstract*/ void add(int field, int amount); + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value.
+ * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + */ + public /*abstract*/ void roll(int field, boolean up); + + /** + * Rolls up or down the specified time field by the given amount. + * A negative amount rolls down. The default implementation is + * call roll(int, boolean) for the specified amount. + * + * Subclasses should override this method to do more intuitiv things. + * + * @param field the time field. One of the time field constants. + * @param amount the amount to roll by, positive for rolling up, + * negative for rolling down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since JDK1.2 + */ + public void roll(int field, int amount) + { + while (amount > 0) + { + roll(field, true); + amount--; + } + while (amount < 0) + { + roll(field, false); + amount++; + } + } + + /** + * Sets the time zone to the specified value. + * @param zone the new time zone + */ + /*public void setTimeZone(TimeZone zone) + { + this.zone = zone; + computeTime(); + computeFields(); + }*/ + + /** + * Gets the time zone of this calendar + * @return the current time zone. + */ + /*public TimeZone getTimeZone() + { + return zone; + }*/ + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @param lenient true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public void setLenient(boolean lenient) + { + this.lenient = lenient; + } + + /** + * Tells if the date/time interpretation is lenient. + * @return true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public boolean isLenient() + { + return lenient; + } + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @param value the first day of week. One of SUNDAY to SATURDAY. + */ + public void setFirstDayOfWeek(int value) + { + firstDayOfWeek = value; + } + + /** + * Gets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @return the first day of week. One of SUNDAY to SATURDAY. + */ + public int getFirstDayOfWeek() + { + return firstDayOfWeek; + } + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @param value the minimal days required in the first week. + */ + public void setMinimalDaysInFirstWeek(int value) + { + minimalDaysInFirstWeek = value; + } + + /** + * Gets how many days are required in the first week of the year. + * @return the minimal days required in the first week. + * @see #setMinimalDaysInFirstWeek + */ + public int getMinimalDaysInFirstWeek() + { + return minimalDaysInFirstWeek; + } + + /** + * Gets the smallest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the smallest value. + */ + public /*abstract*/ int getMinimum(int field); + + /** + * Gets the biggest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the biggest value. + */ + public /*abstract*/ int getMaximum(int field); + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + */ + public /*abstract*/ int getGreatestMinimum(int field); + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. For example this is 28 for DAY_OF_MONTH. + * @param field the time field. One of the time field constants. + * @return the least maximum value. + */ + public /*abstract*/ int getLeastMaximum(int field); + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since jdk1.2 + */ + /*public int getActualMinimum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int min = tmp.getGreatestMinimum(field); + int end = tmp.getMinimum(field); + tmp.set(field, min); + for (; min > end; min--) + { + tmp.add(field, -1); // Try to get smaller + if (tmp.get(field) != min - 1) + break; // Done if not successful + } + return min; + }*/ + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= FIELD_COUNT. + * @since jdk1.2 + */ + /*public int getActualMaximum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int max = tmp.getLeastMaximum(field); + int end = tmp.getMaximum(field); + tmp.set(field, max); + for (; max < end; max++) + { + tmp.add(field, 1); + if (tmp.get(field) != max + 1) + break; + } + return max; + }*/ + + /** + * Compares the time of two calendar instances. + * @param cal the calendar to which the time should be compared. + * @return 0 if the two calendars are set to the same time, + * less than 0 if the time of this calendar is before that of + * cal, or more than 0 if the time of this calendar is after + * that of cal. + * + * @param cal the calendar to compare this instance with. + * @throws NullPointerException if cal is null. + * @throws IllegalArgumentException if either calendar has fields set to + * invalid values. + * @since 1.5 + */ + /*public int compareTo(Calendar cal) + { + long t1 = getTimeInMillis(); + long t2 = cal.getTimeInMillis(); + if(t1 == t2) + return 0; + if(t1 > t2) + return 1; + return -1; + }*/ + + /** + * Return a clone of this object. + */ + public Object clone() + { + try + { + Calendar cal = (Calendar) super.clone(); + cal.fields = (int[]) fields.clone(); + cal.isSet = (boolean[]) isSet.clone(); + return cal; + } + catch (CloneNotSupportedException ex) + { + return null; + } + } + + private static final String[] fieldNames = + { + ",ERA=", ",YEAR=", ",MONTH=", + ",WEEK_OF_YEAR=", + ",WEEK_OF_MONTH=", + ",DAY_OF_MONTH=", + ",DAY_OF_YEAR=", ",DAY_OF_WEEK=", + ",DAY_OF_WEEK_IN_MONTH=", + ",AM_PM=", ",HOUR=", + ",HOUR_OF_DAY=", ",MINUTE=", + ",SECOND=", ",MILLISECOND=", + ",ZONE_OFFSET=", ",DST_OFFSET=" + }; + + /** + * Returns a string representation of this object. It is mainly + * for debugging purposes and its content is implementation + * specific. + */ + /*public String toString() + { + CPStringBuilder sb = new CPStringBuilder(getClass().getName()); + sb.append('['); + sb.append("time="); + if (isTimeSet) + sb.append(time); + else + sb.append("?"); + sb.append(",zone=" + zone); + sb.append(",areFieldsSet=" + areFieldsSet); + for (int i = 0; i < FIELD_COUNT; i++) + { + sb.append(fieldNames[i]); + if (isSet[i]) + sb.append(fields[i]); + else + sb.append("?"); + } + sb.append(",lenient=").append(lenient); + sb.append(",firstDayOfWeek=").append(firstDayOfWeek); + sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek); + sb.append("]"); + return sb.toString(); + }*/ + + /** + * Saves the state of the object to the stream. Ideally we would + * only write the time field, but we need to be compatible with + * earlier versions.
+ * + * This doesn't write the JDK1.1 field nextStamp to the stream, as + * I don't know what it is good for, and because the documentation + * says, that it could be omitted. */ + /*private void writeObject(ObjectOutputStream stream) throws IOException + { + if (! isTimeSet) + computeTime(); + stream.defaultWriteObject(); + }*/ + + /** + * Reads the object back from stream (deserialization). + */ + /*private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (! isTimeSet) + computeTime(); + + if (serialVersionOnStream > 1) + { + // This is my interpretation of the serial number: + // Sun wants to remove all fields from the stream someday + // and will then increase the serialVersion number again. + // We prepare to be compatible. + fields = new int[FIELD_COUNT]; + isSet = new boolean[FIELD_COUNT]; + areFieldsSet = false; + } + }*/ + + /** + * Returns a localised textual representation of the current value + * of the given field using the specified style. If there is no + * applicable textual representation (e.g. the field has a numeric + * value), then null is returned. If one does exist, + * then the value is obtained from {@link #get(int)} and converted + * appropriately. For example, if the MONTH field is + * requested, then get(MONTH) is called. This is then + * converted to a textual representation based on its value and + * the style requested; if the LONG style is requested + * and the returned value is 11 from a + * {@link GregorianCalendar} implementation, then "December" + * is returned. By default, a textual representation is available + * for all fields which have an applicable value obtainable from + * {@link java.text.DateFormatSymbols}. + * + * @param field the calendar field whose textual representation should + * be obtained. + * @param style the style to use; either {@link #LONG} or {@link #SHORT}. + * @param locale the locale to use for translation. + * @return the textual representation of the given field in the specified + * style, or null if none is applicable. + * @throws IllegalArgumentException if field or style + * or invalid, or the calendar is non-lenient + * and has invalid values. + * @throws NullPointerException if locale is null. + * @since 1.6 + */ + /*public String getDisplayName(int field, int style, Locale locale) + { + if (field < 0 || field >= FIELD_COUNT) + throw new IllegalArgumentException("The field value, " + field + + ", is invalid."); + if (style != SHORT && style != LONG) + throw new IllegalArgumentException("The style must be either " + + "short or long."); + if (field == YEAR || field == WEEK_OF_YEAR || + field == WEEK_OF_MONTH || field == DAY_OF_MONTH || + field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH || + field == HOUR || field == HOUR_OF_DAY || field == MINUTE || + field == SECOND || field == MILLISECOND) + return null; + + int value = get(field); + DateFormatSymbols syms = DateFormatSymbols.getInstance(locale); + if (field == ERA) + return syms.getEras()[value]; + if (field == MONTH) + if (style == LONG) + return syms.getMonths()[value]; + else + return syms.getShortMonths()[value]; + if (field == DAY_OF_WEEK) + if (style == LONG) + return syms.getWeekdays()[value]; + else + return syms.getShortWeekdays()[value]; + if (field == AM_PM) + return syms.getAmPmStrings()[value]; + if (field == ZONE_OFFSET) + if (style == LONG) + return syms.getZoneStrings()[value][1]; + else + return syms.getZoneStrings()[value][2]; + if (field == DST_OFFSET) + if (style == LONG) + return syms.getZoneStrings()[value][3]; + else + return syms.getZoneStrings()[value][4]; + + throw new InternalError("Failed to resolve field " + field + + " with style " + style + " for locale " + + locale); + }*/ + + /** + * Returns a map linking all specified textual representations + * of the given field to their numerical values. The textual + * representations included are determined by the specified + * style and locale. For example, if the style LONG + * is specified and the German locale, then the map will + * contain "Montag" to {@link #MONDAY}, "Dienstag" to + * {@link #TUESDAY}, "Mittwoch" to {@link #WEDNESDAY} and + * so on. The default implementation uses the values returned + * by {@link DateFormatSymbols} so, for example, the style + * {@link #ALL_STYLES} and the field {@link #MONTH} will return + * a map filled with the values returned from + * {@link DateFormatSymbols#getMonths()} and + * {@link DateFormatSymbols#getShortMonths()}. If there are + * no textual representations for a given field (usually because + * it is purely numeric, such as the year in the + * {@link GregorianCalendar}), null is returned. + * + * @param field the calendar field whose textual representation should + * be obtained. + * @param style the style to use; either {@link #LONG}, {@link #SHORT} + * or {@link ALL_STYLES}. + * @param locale the locale to use for translation. + * @return a map of the textual representations of the given field in the + * specified style to their numeric values, or null + * if none is applicable. + * @throws IllegalArgumentException if field or style + * or invalid, or the calendar is non-lenient + * and has invalid values. + * @throws NullPointerException if locale is null. + * @since 1.6 + */ + /*public Map getDisplayNames(int field, int style, Locale locale) + { + if (field < 0 || field >= FIELD_COUNT) + throw new IllegalArgumentException("The field value, " + field + + ", is invalid."); + if (style != SHORT && style != LONG && style != ALL_STYLES) + throw new IllegalArgumentException("The style must be either " + + "short, long or all styles."); + if (field == YEAR || field == WEEK_OF_YEAR || + field == WEEK_OF_MONTH || field == DAY_OF_MONTH || + field == DAY_OF_YEAR || field == DAY_OF_WEEK_IN_MONTH || + field == HOUR || field == HOUR_OF_DAY || field == MINUTE || + field == SECOND || field == MILLISECOND) + return null; + + DateFormatSymbols syms = DateFormatSymbols.getInstance(locale); + Map map = new HashMap(); + if (field == ERA) + { + String[] eras = syms.getEras(); + for (int a = 0; a < eras.length; ++a) + map.put(eras[a], a); + return map; + } + if (field == MONTH) + { + if (style == LONG || style == ALL_STYLES) + { + String[] months = syms.getMonths(); + for (int a = 0; a < months.length; ++a) + map.put(months[a], a); + } + if (style == SHORT || style == ALL_STYLES) + { + String[] months = syms.getShortMonths(); + for (int a = 0; a < months.length; ++a) + map.put(months[a], a); + } + return map; + } + if (field == DAY_OF_WEEK) + { + if (style == LONG || style == ALL_STYLES) + { + String[] weekdays = syms.getWeekdays(); + for (int a = SUNDAY; a < weekdays.length; ++a) + map.put(weekdays[a], a); + } + if (style == SHORT || style == ALL_STYLES) + { + String[] weekdays = syms.getShortWeekdays(); + for (int a = SUNDAY; a < weekdays.length; ++a) + map.put(weekdays[a], a); + } + return map; + } + if (field == AM_PM) + { + String[] ampms = syms.getAmPmStrings(); + for (int a = 0; a < ampms.length; ++a) + map.put(ampms[a], a); + return map; + } + if (field == ZONE_OFFSET) + { + String[][] zones = syms.getZoneStrings(); + for (int a = 0; a < zones.length; ++a) + { + if (style == LONG || style == ALL_STYLES) + map.put(zones[a][1], a); + if (style == SHORT || style == ALL_STYLES) + map.put(zones[a][2], a); + } + return map; + } + if (field == DST_OFFSET) + { + String[][] zones = syms.getZoneStrings(); + for (int a = 0; a < zones.length; ++a) + { + if (style == LONG || style == ALL_STYLES) + map.put(zones[a][3], a); + if (style == SHORT || style == ALL_STYLES) + map.put(zones[a][4], a); + } + return map; + } + + throw new InternalError("Failed to resolve field " + field + + " with style " + style + " for locale " + + locale); + }*/ + +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/Constructor.java b/Robust/src/ClassLibrary/MGC/gnu/Constructor.java new file mode 100755 index 00000000..e72a991d --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Constructor.java @@ -0,0 +1,454 @@ +/* java.lang.reflect.Constructor - reflection of Java constructors + Copyright (C) 1998, 2001, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +/*import gnu.java.lang.ClassHelper; +import gnu.java.lang.CPStringBuilder; + +import gnu.java.lang.reflect.MethodSignatureParser; + +import java.lang.annotation.Annotation; +*/ +/** + * The Constructor class represents a constructor of a class. It also allows + * dynamic creation of an object, via reflection. Invocation on Constructor + * objects knows how to do widening conversions, but throws + * {@link IllegalArgumentException} if a narrowing conversion would be + * necessary. You can query for information on this Constructor regardless + * of location, but construction access may be limited by Java language + * access controls. If you can't do it in the compiler, you can't normally + * do it here either.

+ * + * Note: This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,, also available as boolean.class, + * byte.class, etc. These are not to be confused with the + * classes java.lang.Boolean, java.lang.Byte, etc., which are + * real classes.

+ * + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. + * + * @author John Keiser + * @author Eric Blake + * @see Member + * @see Class + * @see java.lang.Class#getConstructor(Class[]) + * @see java.lang.Class#getDeclaredConstructor(Class[]) + * @see java.lang.Class#getConstructors() + * @see java.lang.Class#getDeclaredConstructors() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Constructor// + //extends AccessibleObject + //implements GenericDeclaration, Member +{ + /*private static final int CONSTRUCTOR_MODIFIERS + = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC;*/ + + //private MethodSignatureParser p; + + //VMConstructor cons; + + /** + * This class is uninstantiable outside this package. + */ + Constructor(/*VMConstructor cons*/) + { + //this.cons = cons; + //cons.cons = this; + } + + /*private Constructor() + { + }*/ + + /** + * Gets the class that declared this constructor. + * @return the class that declared this member + */ + public Class/**/ getDeclaringClass() + { + // Inescapable as the VM layer is 1.4 based. + //@SuppressWarnings("unchecked") + //Class/**/ declClass = /*(Class)*/ cons.getDeclaringClass(); + //return declClass; + return null; + } + + /** + * Gets the name of this constructor (the non-qualified name of the class + * it was declared in). + * @return the name of this constructor + */ + public String getName() + { + return null; //cons.getDeclaringClass().getName(); + } + + /** + * Gets the modifiers this constructor uses. Use the Modifier + * class to interpret the values. A constructor can only have a subset of the + * following modifiers: public, private, protected. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + /*public int getModifiers() + { + return cons.getModifiersInternal() & CONSTRUCTOR_MODIFIERS; + }*/ + + /** + * Return true if this constructor is synthetic, false otherwise. + * A synthetic member is one which is created by the compiler, + * and which does not appear in the user's source code. + * @since 1.5 + */ + /*public boolean isSynthetic() + { + return (cons.getModifiersInternal() & Modifier.SYNTHETIC) != 0; + }*/ + + /** + * Return true if this is a varargs constructor, that is if + * the constructor takes a variable number of arguments. + * @since 1.5 + */ + /*public boolean isVarArgs() + { + return (cons.getModifiersInternal() & Modifier.VARARGS) != 0; + }*/ + + /** + * Get the parameter list for this constructor, in declaration order. If the + * constructor takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the constructor's parameters + */ + public Class/**/[] getParameterTypes() + { + return /*(Class[])*/ null; //cons.getParameterTypes(); + } + + /** + * Get the exception types this constructor says it throws, in no particular + * order. If the constructor has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the constructor's throws clause + */ + /*public Class[] getExceptionTypes() + { + return (Class[]) cons.getExceptionTypes(); + }*/ + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Constructors are semantically equivalent if they have the same + * declaring class and the same parameter list. This ignores different + * exception clauses, but since you can't create a Method except through the + * VM, this is just the == relation. + * + * @param o the object to compare to + * @return true if they are equal; false if not. + */ + public boolean equals(Object o) + { + return false; //cons.equals(o); + } + + /** + * Get the hash code for the Constructor. The Constructor hash code is the + * hash code of the declaring class's name. + * + * @return the hash code for the object + */ + public int hashCode() + { + return getName().hashCode(); + } + + /** + * Get a String representation of the Constructor. A Constructor's String + * representation is "<modifier> <classname>(<paramtypes>) + * throws <exceptions>", where everything after ')' is omitted if + * there are no exceptions.
Example: + * public java.io.FileInputStream(java.lang.Runnable) + * throws java.io.FileNotFoundException + * + * @return the String representation of the Constructor + */ + /*public String toString() + { + // 128 is a reasonable buffer initial size for constructor + CPStringBuilder sb = new CPStringBuilder(128); + Modifier.toString(getModifiers(), sb).append(' '); + sb.append(getDeclaringClass().getName()).append('('); + Class[] c = getParameterTypes(); + if (c.length > 0) + { + sb.append(ClassHelper.getUserName(c[0])); + for (int i = 1; i < c.length; i++) + sb.append(',').append(ClassHelper.getUserName(c[i])); + } + sb.append(')'); + c = getExceptionTypes(); + if (c.length > 0) + { + sb.append(" throws ").append(c[0].getName()); + for (int i = 1; i < c.length; i++) + sb.append(',').append(c[i].getName()); + } + return sb.toString(); + }*/ + + /*static + void addTypeParameters(CPStringBuilder sb, TypeVariable[] typeArgs) + { + if (typeArgs.length == 0) + return; + sb.append('<'); + for (int i = 0; i < typeArgs.length; ++i) + { + if (i > 0) + sb.append(','); + sb.append(typeArgs[i]); + } + sb.append("> "); + }*/ + + /*public String toGenericString() + { + CPStringBuilder sb = new CPStringBuilder(128); + Modifier.toString(getModifiers(), sb).append(' '); + addTypeParameters(sb, getTypeParameters()); + sb.append(getDeclaringClass().getName()).append('('); + Type[] types = getGenericParameterTypes(); + if (types.length > 0) + { + sb.append(types[0]); + for (int i = 1; i < types.length; ++i) + sb.append(',').append(types[i]); + } + sb.append(')'); + types = getGenericExceptionTypes(); + if (types.length > 0) + { + sb.append(" throws ").append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } + return sb.toString(); + }*/ + + /** + * Create a new instance by invoking the constructor. Arguments are + * automatically unwrapped and widened, if needed.

+ * + * If this class is abstract, you will get an + * InstantiationException. If the constructor takes 0 + * arguments, you may use null or a 0-length array for args.

+ * + * If this Constructor enforces access control, your runtime context is + * evaluated, and you may have an IllegalAccessException if + * you could not create this object in similar compiled code. If the class + * is uninitialized, you trigger class initialization, which may end in a + * ExceptionInInitializerError.

+ * + * Then, the constructor is invoked. If it completes normally, the return + * value will be the new object. If it completes abruptly, the exception is + * wrapped in an InvocationTargetException. + * + * @param args the arguments to the constructor + * @return the newly created object + * @throws IllegalAccessException if the constructor could not normally be + * called by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * or if the arguments types are wrong even with a widening + * conversion + * @throws InstantiationException if the class is abstract + * @throws InvocationTargetException if the constructor throws an exception + * @throws ExceptionInInitializerError if construction triggered class + * initialization, which then failed + */ + public Object/*T*/ newInstance(Object[]/*...*/ args) + //throws InstantiationException, IllegalAccessException, + // InvocationTargetException + { + // Inescapable as the VM layer is 1.4 based. + //@SuppressWarnings("unchecked") + Object/*T*/ ins = null; ///*(T)*/ cons.construct(args); + return ins; + } + + /** + * Returns an array of TypeVariable objects that represents + * the type variables declared by this constructor, in declaration order. + * An array of size zero is returned if this constructor has no type + * variables. + * + * @return the type variables associated with this constructor. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /*public TypeVariable>[] getTypeParameters() + { + if (p == null) + { + String sig = cons.getSignature(); + if (sig == null) + return new TypeVariable[0]; + p = new MethodSignatureParser(this, sig); + } + return p.getTypeParameters(); + }*/ + + /** + * Returns an array of Type objects that represents + * the exception types declared by this constructor, in declaration order. + * An array of size zero is returned if this constructor declares no + * exceptions. + * + * @return the exception types declared by this constructor. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /*public Type[] getGenericExceptionTypes() + { + if (p == null) + { + String sig = cons.getSignature(); + if (sig == null) + return getExceptionTypes(); + p = new MethodSignatureParser(this, sig); + } + return p.getGenericExceptionTypes(); + }*/ + + /** + * Returns an array of Type objects that represents + * the parameter list for this constructor, in declaration order. + * An array of size zero is returned if this constructor takes no + * parameters. + * + * @return a list of the types of the constructor's parameters + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /*public Type[] getGenericParameterTypes() + { + if (p == null) + { + String sig = cons.getSignature(); + if (sig == null) + return getParameterTypes(); + p = new MethodSignatureParser(this, sig); + } + return p.getGenericParameterTypes(); + }*/ + + /** + *

+ * Return an array of arrays representing the annotations on each + * of the constructor's parameters. The outer array is aligned against + * the parameters of the constructors and is thus equal in length to + * the number of parameters (thus having a length zero if there are none). + * Each array element in the outer array contains an inner array which + * holds the annotations. This array has a length of zero if the parameter + * has no annotations. + *

+ *

+ * The returned annotations are serialized. Changing the annotations has + * no affect on the return value of future calls to this method. + *

+ * + * @return an array of arrays which represents the annotations used on the + * parameters of this constructor. The order of the array elements + * matches the declaration order of the parameters. + * @since 1.5 + */ + /*public Annotation[][] getParameterAnnotations() + { + return cons.getParameterAnnotations(); + }*/ + + /** + * Returns the element's annotation for the specified annotation type, + * or null if no such annotation exists. + * + * @param annotationClass the type of annotation to look for. + * @return this element's annotation for the specified type, or + * null if no such annotation exists. + * @throws NullPointerException if the annotation class is null. + */ + /*public T getAnnotation(Class annotationClass) + { + // Inescapable as the VM layer is 1.4 based. + @SuppressWarnings("unchecked") + T ann = (T) cons.getAnnotation(annotationClass); + return ann; + }*/ + + /** + * Returns all annotations directly defined by the element. If there are + * no annotations directly associated with the element, then a zero-length + * array will be returned. The returned array may be modified by the client + * code, but this will have no effect on the annotation content of this + * class, and hence no effect on the return value of this method for + * future callers. + * + * @return the annotations directly defined by the element. + * @since 1.5 + */ + /*public Annotation[] getDeclaredAnnotations() + { + return cons.getDeclaredAnnotations(); + }*/ + +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/Date.java b/Robust/src/ClassLibrary/MGC/gnu/Date.java new file mode 100644 index 00000000..801c3778 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Date.java @@ -0,0 +1,1257 @@ +/* java.util.Date + Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +/*import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +*/ +/** + *

+ * This class represents a specific time in milliseconds since the epoch. + * The epoch is 1970, January 1 00:00:00.0000 UTC. + *

+ *

+ * Date is intended to reflect universal time coordinate (UTC), + * but this depends on the underlying host environment. Most operating systems + * don't handle the leap second, which occurs about once every year or + * so. The leap second is added to the last minute of the day on either + * the 30th of June or the 31st of December, creating a minute 61 seconds + * in length. + *

+ *

+ * The representations of the date fields are as follows: + *

    + *
  • + * Years are specified as the difference between the year + * and 1900. Thus, the final year used is equal to + * 1900 + y, where y is the input value. + *
  • + *
  • + * Months are represented using zero-based indexing, + * making 0 January and 11 December. + *
  • + *
  • + * Dates are represented with the usual values of + * 1 through to 31. + *
  • + *
  • + * Hours are represented in the twenty-four hour clock, + * with integer values from 0 to 23. 12am is 0, and + * 12pm is 12. + *
  • + *
  • + * Minutes are again as usual, with values from 0 to 59. + *
  • + *
  • + * Seconds are represented with the values 0 through to 61, + * with 60 and 61 being leap seconds (as per the ISO C standard). + *
  • + *
+ *

+ *

+ * Prior to JDK 1.1, this class was the sole class handling date and time + * related functionality. However, this particular solution was not + * amenable to internationalization. The new Calendar + * class should now be used to handle dates and times, with Date + * being used only for values in milliseconds since the epoch. The + * Calendar class, and its concrete implementations, handle + * the interpretation of these values into minutes, hours, days, months + * and years. The formatting and parsing of dates is left to the + * DateFormat class, which is able to handle the different + * types of date format which occur in different locales. + *

+ * + * @see Calendar + * @see GregorianCalendar + * @see java.text.DateFormat + * @author Jochen Hoenicke + * @author Per Bothner (bothner@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class Date + //implements Cloneable, Comparable, Serializable +{ + /** + * This is the serialization UID for this class + * for compatability with Sun's JDK. + */ + private static final long serialVersionUID = 7523967970034938905L; + + /** + * The time in milliseconds since the epoch. + */ + private transient long time; + + /** + * An array of week names used to map names to integer values. + */ + private static final String[] weekNames = { "Sun", "Mon", "Tue", "Wed", + "Thu", "Fri", "Sat" }; + /** + * An array of month names used to map names to integer values. + */ + private static final String[] monthNames = { "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" }; + /** + * Creates a new Date Object representing the current time. + */ + public Date() + { + time = System.currentTimeMillis(); + } + + /** + * Creates a new Date Object representing the given time. + * + * @param time the time in milliseconds since the epoch. + */ + public Date(long time) + { + this.time = time; + } + + /** + * Creates a new Date Object representing the given time. + * + * @deprecated use new GregorianCalendar(year+1900, month, + * day) instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param day the day as a value between 0 and 31. + */ + public Date(int year, int month, int day) + { + this(year, month, day, 0, 0, 0); + } + + /** + * Creates a new Date Object representing the given time. + * + * @deprecated use new GregorianCalendar(year+1900, month, + * day, hour, min) instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param day the day as a value between 0 and 31. + * @param hour the hour as a value between 0 and 23, in 24-hour + * clock notation. + * @param min the minute as a value between 0 and 59. + */ + public Date(int year, int month, int day, int hour, int min) + { + this(year, month, day, hour, min, 0); + } + + /** + * Creates a new Date Object representing the given time. + * + * @deprecated use new GregorianCalendar(year+1900, month, + * day, hour, min, sec) instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param day the day as a value between 0 and 31. + * @param hour the hour as a value between 0 and 23, in 24-hour + * clock notation. + * @param min the minute as a value between 0 and 59. + * @param sec the second as a value between 0 and 61 (with 60 + * and 61 being leap seconds). + */ + public Date(int year, int month, int day, int hour, int min, int sec) + { + GregorianCalendar cal = + new GregorianCalendar(year + 1900, month, day, hour, min, sec); + time = cal.getTimeInMillis(); + } + + /** + * Creates a new Date from the given string representation. This + * does the same as new Date(Date.parse(s)) + * @see #parse + * @deprecated use java.text.DateFormat.parse(s) instead. + */ + /*public Date(String s) + { + time = parse(s); + }*/ + + /** + * Returns a copy of this Date object. + * + * @return a copy, or null if the object couldn't be + * cloned. + * @see Object#clone() + */ + /*public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException ex) + { + return null; + } + }*/ + + /** + * Returns the number of milliseconds since the epoch + * specified by the given arguments. The arguments are + * interpreted relative to UTC rather than the local + * time zone. + * + * @deprecated Use Calendar with a UTC + * TimeZone instead. + * @param year the difference between the required year and 1900. + * @param month the month as a value between 0 and 11. + * @param date the day as a value between 0 and 31. + * @param hrs the hour as a value between 0 and 23, in 24-hour + * clock notation. + * @param min the minute as a value between 0 and 59. + * @param sec the second as a value between 0 and 61 (with 60 + * and 61 being leap seconds). + * @return the time in milliseconds since the epoch. + */ + /*public static long UTC(int year, int month, int date, + int hrs, int min, int sec) + { + GregorianCalendar cal = + new GregorianCalendar(year + 1900, month, date, hrs, min, sec); + cal.set(Calendar.ZONE_OFFSET, 0); + cal.set(Calendar.DST_OFFSET, 0); + return cal.getTimeInMillis(); + }*/ + + /** + * Gets the time represented by this object. + * + * @return the time in milliseconds since the epoch. + */ + public long getTime() + { + return time; + } + + /** + * Returns the number of minutes offset used with UTC to give the time + * represented by this object in the current time zone. The date information + * from this object is also used to determine whether or not daylight savings + * time is in effect. For example, the offset for the UK would be 0 if the + * month of the date object was January, and 1 if the month was August. + * + * @deprecated use + * Calendar.get(Calendar.ZONE_OFFSET)+Calendar.get(Calendar.DST_OFFSET) + * instead. + * @return The time zone offset in minutes of the local time zone + * relative to UTC. The time represented by this object is used to + * determine if we should use daylight savings. + */ + /*public int getTimezoneOffset() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return - (cal.get(Calendar.ZONE_OFFSET) + + cal.get(Calendar.DST_OFFSET)) / (60 * 1000); + }*/ + + /** + * Sets the time which this object should represent. + * + * @param time the time in milliseconds since the epoch. + */ + public void setTime(long time) + { + this.time = time; + } + + /** + * Tests if this date is after the specified date. + * + * @param when the other date + * @return true, if the date represented by this object is + * strictly later than the time represented by when. + */ + public boolean after(Date when) + { + return time > when.time; + } + + /** + * Tests if this date is before the specified date. + * + * @param when the other date + * @return true, if the date represented by when is strictly later + * than the time represented by this object. + */ + public boolean before(Date when) + { + return time < when.time; + } + + /** + * Compares two dates for equality. + * + * @param obj the object to compare. + * @return true, if obj is a Date object and the time represented + * by obj is exactly the same as the time represented by this + * object. + */ + public boolean equals(Object obj) + { + return (obj instanceof Date && time == ((Date) obj).time); + } + + /** + * Compares two dates. + * + * @param when the other date. + * @return 0, if the date represented + * by obj is exactly the same as the time represented by this + * object, a negative if this Date is before the other Date, and + * a positive value otherwise. + */ + public int compareTo(Date when) + { + return (time < when.time) ? -1 : (time == when.time) ? 0 : 1; + } + + /** + * Computes the hash code of this Date as the + * XOR of the most significant and the least significant + * 32 bits of the 64 bit milliseconds value. + * + * @return the hash code. + */ + public int hashCode() + { + return (int) time ^ (int) (time >>> 32); + } + + /** + *

+ * Returns a string representation of this date using + * the following date format: + *

+ *

+ * day mon dd hh:mm:ss zz yyyy + *

+ *

where the fields used here are: + *

    + *
  • + * day -- the day of the week + * (Sunday through to Saturday). + *
  • + *
  • + * mon -- the month (Jan to Dec). + *
  • + *
  • + * dd -- the day of the month + * as two decimal digits (01 to 31). + *
  • + *
  • + * hh -- the hour of the day + * as two decimal digits in 24-hour clock notation + * (01 to 23). + *
  • + *
  • + * mm -- the minute of the day + * as two decimal digits (01 to 59). + *
  • + *
  • + * ss -- the second of the day + * as two decimal digits (01 to 61). + *
  • + *
  • + * zz -- the time zone information if available. + * The possible time zones used include the abbreviations + * recognised by parse() (e.g. GMT, CET, etc.) + * and may reflect the fact that daylight savings time is in + * effect. The empty string is used if there is no time zone + * information. + *
  • + *
  • + * yyyy -- the year as four decimal digits. + *
  • + *
+ *

+ * The DateFormat class should now be + * preferred over using this method. + *

+ * + * @return A string of the form 'day mon dd hh:mm:ss zz yyyy' + * @see #parse(String) + * @see DateFormat + */ + /*public String toString() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + String day = "0" + cal.get(Calendar.DATE); + String hour = "0" + cal.get(Calendar.HOUR_OF_DAY); + String min = "0" + cal.get(Calendar.MINUTE); + String sec = "0" + cal.get(Calendar.SECOND); + String year = "000" + cal.get(Calendar.YEAR); + return weekNames[cal.get(Calendar.DAY_OF_WEEK) - 1] + " " + + monthNames[cal.get(Calendar.MONTH)] + " " + + day.substring(day.length() - 2) + " " + + hour.substring(hour.length() - 2) + ":" + + min.substring(min.length() - 2) + ":" + + sec.substring(sec.length() - 2) + " " + + + cal.getTimeZone().getDisplayName(cal.getTimeZone().inDaylightTime(this), + TimeZone.SHORT) + " " + + year.substring(year.length() - 4); + }*/ + + /** + * Returns a locale-dependent string representation of this + * Date object. + * + * @deprecated Use DateFormat.format(Date) + * @return A locale-dependent string representation. + * @see #parse(String) + * @see DateFormat + */ + /*public String toLocaleString() + { + return java.text.DateFormat.getInstance().format(this); + }*/ + + /** + *

+ * Returns a string representation of this Date + * object using GMT rather than the local timezone. + * The following date format is used: + *

+ *

+ * d mon yyyy hh:mm:ss GMT + *

+ *

where the fields used here are: + *

    + *
  • + * d -- the day of the month + * as one or two decimal digits (1 to 31). + *
  • + *
  • + * mon -- the month (Jan to Dec). + *
  • + *
  • + * yyyy -- the year as four decimal digits. + *
  • + *
  • + * hh -- the hour of the day + * as two decimal digits in 24-hour clock notation + * (01 to 23). + *
  • + *
  • + * mm -- the minute of the day + * as two decimal digits (01 to 59). + *
  • + *
  • + * ss -- the second of the day + * as two decimal digits (01 to 61). + *
  • + *
  • + * GMT -- the literal string "GMT" + * indicating Greenwich Mean Time as opposed to + * the local timezone. + *
  • + *
+ * + * @deprecated Use DateFormat.format(Date) with a GMT TimeZone. + * @return A string of the form 'd mon yyyy hh:mm:ss GMT' using + * GMT as opposed to the local timezone. + * @see #parse(String) + * @see DateFormat + */ + /*public String toGMTString() + { + java.text.DateFormat format = java.text.DateFormat.getInstance(); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + return format.format(this); + }*/ + + /** + * Parses the time zone string. + * + * @param tok The token containing the time zone. + * @param sign The sign (+ or -) used by the time zone. + * @return An integer representing the number of minutes offset + * from GMT for the time zone. + */ + /*private static int parseTz(String tok, char sign) + throws IllegalArgumentException + { + int num; + + try + { + // parseInt doesn't handle '+' so strip off sign. + num = Integer.parseInt(tok.substring(1)); + } + catch (NumberFormatException ex) + { + throw new IllegalArgumentException(tok); + } + + // Convert hours to minutes. + if (num < 24) + num *= 60; + else + num = (num / 100) * 60 + num % 100; + + return sign == '-' ? -num : num; + }*/ + + /** + * Parses the month string. + * + * @param tok the token containing the month. + * @return An integer between 0 and 11, representing + * a month from January (0) to December (11), + * or -1 if parsing failed. + */ + /*private static int parseMonth(String tok) + { + // Initialize strings for month names. + // We could possibly use the fields of DateFormatSymbols but that is + // localized and thus might not match the English words specified. + String months[] = { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", + "JUNE", "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", + "NOVEMBER", "DECEMBER" }; + + int i; + for (i = 0; i < 12; i++) + if (months[i].startsWith(tok)) + return i; + + // Return -1 if not found. + return -1; + }*/ + + /** + * Parses the day of the week string. + * + * @param tok the token containing the day of the week. + * @return true if the token was parsed successfully. + */ + /*private static boolean parseDayOfWeek(String tok) + { + // Initialize strings for days of the week names. + // We could possibly use the fields of DateFormatSymbols but that is + // localized and thus might not match the English words specified. + String daysOfWeek[] = { "SUNDAY", "MONDAY", "TUESDAY", "WEDNESDAY", + "THURSDAY", "FRIDAY", "SATURDAY" }; + + int i; + for (i = 0; i < 7; i++) + if (daysOfWeek[i].startsWith(tok)) + return true; + + return false; + }*/ + + /** + *

+ * Parses a String and returns the time, in milliseconds since the + * epoch, it represents. Most syntaxes are handled, including + * the IETF date standard "day, dd mon yyyy hh:mm:ss zz" (see + * toString() for definitions of these fields). + * Standard U.S. time zone abbreviations are recognised, in + * addition to time zone offsets in positive or negative minutes. + * If a time zone is specified, the specified time is assumed to + * be in UTC and the appropriate conversion is applied, following + * parsing, to convert this to the local time zone. If no zone + * is specified, the time is assumed to already be in the local + * time zone. + *

+ *

+ * The method parses the string progressively from left to right. + * At the end of the parsing process, either a time is returned + * or an IllegalArgumentException is thrown to signify + * failure. The ASCII characters A-Z, a-z, 0-9, and ',', '+', '-', + * ':' and '/' are the only characters permitted within the string, + * besides whitespace and characters enclosed within parantheses + * '(' and ')'. + *

+ *

+ * A sequence of consecutive digits are recognised as a number, + * and interpreted as follows: + *

    + *
  • + * A number preceded by a sign (+ or -) is taken to be a time zone + * offset. The time zone offset can be specified in either hours + * or minutes. The former is assumed if the number is less than 24. + * Otherwise, the offset is assumed to be in minutes. A - indicates + * a time zone west of GMT, while a + represents a time zone to the + * east of GMT. The time zones are always assumed to be relative + * to GMT, and a (redundant) specification of this can be included + * with the time zone. For example, '-9', 'utc-9' and 'GMT-9' all + * represent a time zone nine hours west of GMT. Similarly, + * '+4', 'ut+4' and 'UTC+4' all give 4 hours east of GMT. + *
  • + *
  • + * A number equal to or greater than 70 is regarded as a year specification. + * Values lower than 70 are only assumed to indicate a year if both the + * day of the month and the month itself have already been recognised. + * Year values less than 100 are interpreted as being relative to the current + * century when the Date class is initialised.. Given a century, + * x, the year is assumed to be within the range x - 80 to x + 19. The value + * itself is then used as a match against the two last digits of one of these + * years. For example, take x to be 2004. A two-digit year is assumed to fall + * within the range x - 80 (1924) and x + 19 (2023). Thus, any intepreted value + * between 0 and 23 is assumed to be 2000 to 2023 and values between 24 and 99 + * are taken as being 1924 to 1999. This only applies for the case of 2004. + * With a different year, the values will be interpreted differently. 2005 + * will used 0 to 24 as 2000 to 2024 and 25 to 99 as 1925 to 1999, for example. + * This behaviour differs from that of SimpleDateFormat and is + * time-dependent (a two-digit year will be interpreted differently depending + * on the time the code is run). + *
  • + *
  • + * Numbers followed by a colon are interpreted by first an hour, and then + * as a minute, once an hour has been found. + *
  • + *
  • + *
  • + * Numbers followed by a slash are regarded first as a month, and then as + * a day of the month once the month has been found. This follows the + * U.S. date format of mm/dd, rather than the European dd/mm. Months + * are converted to the recognised value - 1 before storage, in order + * to put the number within the range 0 to 11. + *
  • + *
  • + * Numbers followed by commas, whitespace, hyphens or the end of the string + * are interpreted in the following order: hour, minute, second, day of month. + * The first type not already recognised in the current string being parsed is + * assumed. + *
  • + *
+ *

+ *

+ * A sequence of consecutive alphabetic characters is recognised as a word, + * and interpreted as follows, in a case-insentive fashion: + *

    + *
  • + * The characters 'AM' or 'PM' restrict the hour value to a value between 0 + * and 12. In the latter case, 12 is added to the hour value before storage. + *
  • + *
  • + * Any words which match any prefix of one of the days of the week ('Monday', + * 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' and 'Sunday'), + * are simply ignored. + *
  • + *
  • + * Any words which match any prefix of one of the months of the year ('January', + * 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', + * 'October', 'November', 'December') are recognised and interpreted as the + * appropriate value between 0 and 11. The first match made against a + * month is the one used, in the order specified here. For example, 'Ma' is + * intepreted as 'March' (2) and not as 'May' (4). Similarly, 'Ju' is 'June', + * and not 'July'. + *
  • + *
  • + * The words 'GMT', 'UT' and 'UTC' are interpreted as specifying UTC as the + * time zone in use for this date. + *
  • + *
  • + * The word pairs 'EST'/'EDT', 'CST'/'CDT', 'MST'/'MDT' and 'PST'/'PDT' are + * interpreted as the appropriate U.S. time zone abbreviation. Each pair + * is the standard and daylight savings time zone specification, respectively, + * for each zone within the U.S, these being Eastern Standard/Daylight Time + * (-5), Central Standard/Daylight Time (-6), Mountain Standard/Daylight Time + * (-7) and Pacific Standard/Daylight Time (-8). + *
  • + *
+ * + * @param string The String to parse. + * @return The time in milliseconds since the epoch. + * @throws IllegalArgumentException if the string fails to parse. + * @deprecated Use DateFormat.parse(String) + * @see #toString() + * @see SimpleDateFormat + */ + /*public static long parse(String string) + { + // Initialize date/time fields before parsing begins. + int year = -1; + int month = -1; + int day = -1; + int hour = -1; + int minute = -1; + int second = -1; + int timezone = 0; + boolean localTimezone = true; + + // Trim out any nested stuff in parentheses now to make parsing easier. + CPStringBuilder buf = new CPStringBuilder(); + int parenNesting = 0; + int len = string.length(); + for (int i = 0; i < len; i++) + { + char ch = string.charAt(i); + if (ch >= 'a' && ch <= 'z') + ch -= 'a' - 'A'; + if (ch == '(') + parenNesting++; + else if (parenNesting == 0) + buf.append(ch); + else if (ch == ')') + parenNesting--; + } + int tmpMonth; + + // Make all chars upper case to simplify comparisons later. + // Also ignore commas; treat them as delimiters. + StringTokenizer strtok = new StringTokenizer(buf.toString(), " \t\n\r,"); + + while (strtok.hasMoreTokens()) + { + String tok = strtok.nextToken(); + char firstch = tok.charAt(0); + if ((firstch == '+' || firstch == '-') && year >= 0) + { + timezone = parseTz(tok, firstch); + localTimezone = false; + } + else if (firstch >= '0' && firstch <= '9') + { + int lastPunct = -1; + while (tok != null && tok.length() > 0) + { + int punctOffset = tok.length(); + int num = 0; + int punct; + for (int i = 0; ; i++) + { + if (i >= punctOffset) + { + punct = -1; + break; + } + else + { + punct = tok.charAt(i); + if (punct >= '0' && punct <= '9') + { + if (num > 999999999) // in case of overflow + throw new IllegalArgumentException(tok); + num = 10 * num + (punct - '0'); + } + else + { + punctOffset = i; + break; + } + } + + } + + if (punct == ':') + { + if (hour < 0) + hour = num; + else + minute = num; + } + else if (lastPunct == ':' && hour >= 0 && (minute < 0 || second < 0)) + { + if (minute < 0) + minute = num; + else + second = num; + } + else if ((num >= 70 + && (punct == ' ' || punct == ',' + || punct == '/' || punct < 0)) + || (num < 70 && day >= 0 && month >= 0 && year < 0)) + { + if (num >= 100) + year = num; + else + { + int curYear = 1900 + new Date().getYear(); + int firstYear = curYear - 80; + year = firstYear / 100 * 100 + num; + if (year < firstYear) + year += 100; + } + } + else if (punct == '/') + { + if (month < 0) + month = num - 1; + else + day = num; + } + else if (hour >= 0 && minute < 0) + minute = num; + else if (minute >= 0 && second < 0) + second = num; + else if (day < 0) + day = num; + else + throw new IllegalArgumentException(tok); + + // Advance string if there's more to process in this token. + if (punct < 0 || punctOffset + 1 >= tok.length()) + tok = null; + else + tok = tok.substring(punctOffset + 1); + lastPunct = punct; + } + } + else if (firstch >= 'A' && firstch <= 'Z') + { + if (tok.equals("AM")) + { + if (hour < 1 || hour > 12) + throw new IllegalArgumentException(tok); + if (hour == 12) + hour = 0; + } + else if (tok.equals("PM")) + { + if (hour < 1 || hour > 12) + throw new IllegalArgumentException(tok); + if (hour < 12) + hour += 12; + } + else if (parseDayOfWeek(tok)) + { // Ignore it; throw the token away. + } + else if (tok.equals("UT") || tok.equals("UTC") || tok.equals("GMT")) + localTimezone = false; + else if (tok.startsWith("UT") || tok.startsWith("GMT")) + { + int signOffset = 3; + if (tok.charAt(1) == 'T' && tok.charAt(2) != 'C') + signOffset = 2; + + char sign = tok.charAt(signOffset); + if (sign != '+' && sign != '-') + throw new IllegalArgumentException(tok); + + timezone = parseTz(tok.substring(signOffset), sign); + localTimezone = false; + } + else if ((tmpMonth = parseMonth(tok)) >= 0) + month = tmpMonth; + else if (tok.length() == 3 && tok.charAt(2) == 'T') + { + // Convert timezone offset from hours to minutes. + char ch = tok.charAt(0); + if (ch == 'E') + timezone = -5 * 60; + else if (ch == 'C') + timezone = -6 * 60; + else if (ch == 'M') + timezone = -7 * 60; + else if (ch == 'P') + timezone = -8 * 60; + else + throw new IllegalArgumentException(tok); + + // Shift 60 minutes for Daylight Savings Time. + if (tok.charAt(1) == 'D') + timezone += 60; + else if (tok.charAt(1) != 'S') + throw new IllegalArgumentException(tok); + + localTimezone = false; + } + else + throw new IllegalArgumentException(tok); + } + else + throw new IllegalArgumentException(tok); + } + + // Unspecified hours, minutes, or seconds should default to 0. + if (hour < 0) + hour = 0; + if (minute < 0) + minute = 0; + if (second < 0) + second = 0; + + // Throw exception if any other fields have not been recognized and set. + if (year < 0 || month < 0 || day < 0) + throw new IllegalArgumentException("Missing field"); + + // Return the time in either local time or relative to GMT as parsed. + // If no time-zone was specified, get the local one (in minutes) and + // convert to milliseconds before adding to the UTC. + GregorianCalendar cal + = new GregorianCalendar(year, month, day, hour, minute, second); + if (!localTimezone) + { + cal.set(Calendar.ZONE_OFFSET, timezone * 60 * 1000); + cal.set(Calendar.DST_OFFSET, 0); + } + return cal.getTimeInMillis(); + }*/ + + /** + * Returns the difference between the year represented by this + * Date object and 1900. + * + * @return the year minus 1900 represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.YEAR) + * instead. Note the 1900 difference in the year. + * @see Calendar + * @see #setYear(int) + */ + /*public int getYear() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.YEAR) - 1900; + }*/ + + /** + * Sets the year to the specified year, plus 1900. The other + * fields are only altered as required to match the same date + * and time in the new year. Usually, this will mean that + * the fields are not changed at all, but in the case of + * a leap day or leap second, the fields will change in + * relation to the existence of such an event in the new year. + * For example, if the date specifies February the 29th, 2000, + * then this will become March the 1st if the year is changed + * to 2001, as 2001 is not a leap year. Similarly, a seconds + * value of 60 or 61 may result in the seconds becoming 0 and + * the minute increasing by 1, if the new time does not include + * a leap second. + * + * @param year the year minus 1900. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.YEAR, year) instead. Note about the 1900 + * difference in year. + * @see #getYear() + * @see Calendar + */ + /*public void setYear(int year) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.YEAR, 1900 + year); + time = cal.getTimeInMillis(); + }*/ + + /** + * Returns the month represented by this Date object, + * as a value between 0 (January) and 11 (December). + * + * @return the month represented by this date object (zero based). + * @deprecated Use Calendar instead of Date, and use get(Calendar.MONTH) + * instead. + * @see #setMonth(int) + * @see Calendar + */ + /*public int getMonth() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.MONTH); + }*/ + + /** + * Sets the month to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new month. In most + * cases, the other fields won't change at all. However, + * in the case of a shorter month or a leap second, values + * may be adjusted. For example, if the day of the month + * is currently 31, and the month value is changed from + * January (0) to September (8), the date will become + * October the 1st, as September only has 30 days. Similarly, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1, if the new time does + * not include a leap second. + * + * @param month the month, with a zero-based index + * from January. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.MONTH, month) instead. + * @see #getMonth() + * @see Calendar + */ + /*public void setMonth(int month) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.MONTH, month); + time = cal.getTimeInMillis(); + }*/ + + /** + * Returns the day of the month of this Date + * object, as a value between 0 and 31. + * + * @return the day of month represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.DATE) + * instead. + * @see Calendar + * @see #setDate(int) + */ + /*public int getDate() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.DATE); + }*/ + + /** + * Sets the date to the given value. The other + * fields are only altered as necessary to match + * the same date and time on the new day of the month. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second or the day being out of + * the range of the current month, values + * may be adjusted. For example, if the day of the month + * is currently 30 and the month is June, a new day of the + * month value of 31 will cause the month to change to July, + * as June only has 30 days . Similarly, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1, if the new time does + * not include a leap second. + * + * @param date the date. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.DATE, date) instead. + * @see Calendar + * @see #getDate() + */ + /*public void setDate(int date) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.DATE, date); + time = cal.getTimeInMillis(); + }*/ + + /** + * Returns the day represented by this Date + * object as an integer between 0 (Sunday) and 6 (Saturday). + * + * @return the day represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.DAY_OF_WEEK) + * instead. + * @see Calendar + */ + /*public int getDay() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + // For Calendar, Sunday is 1. For Date, Sunday is 0. + return cal.get(Calendar.DAY_OF_WEEK) - 1; + }*/ + + /** + * Returns the hours represented by this Date + * object as an integer between 0 and 23. + * + * @return the hours represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.HOUR_OF_DAY) + * instead. + * @see Calendar + * @see #setHours(int) + */ + /*public int getHours() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.HOUR_OF_DAY); + }*/ + + /** + * Sets the hours to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new hour. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second, values + * may be adjusted. For example, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1 if the new hour does + * not contain a leap second. + * + * @param hours the hours. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.HOUR_OF_DAY, hours) instead. + * @see Calendar + * @see #getHours() + */ + /*public void setHours(int hours) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.HOUR_OF_DAY, hours); + time = cal.getTimeInMillis(); + }*/ + + /** + * Returns the number of minutes represented by the Date + * object, as an integer between 0 and 59. + * + * @return the minutes represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.MINUTE) + * instead. + * @see Calendar + * @see #setMinutes(int) + */ + /*public int getMinutes() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.MINUTE); + }*/ + + /** + * Sets the minutes to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new minute. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second, values + * may be adjusted. For example, + * a seconds value of 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1 if the new minute does + * not contain a leap second. + * + * @param minutes the minutes. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.MINUTE, minutes) instead. + * @see Calendar + * @see #getMinutes() + */ + /*public void setMinutes(int minutes) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.MINUTE, minutes); + time = cal.getTimeInMillis(); + }*/ + + /** + * Returns the number of seconds represented by the Date + * object, as an integer between 0 and 61 (60 and 61 being leap seconds). + * + * @return the seconds represented by this date object. + * @deprecated Use Calendar instead of Date, and use get(Calendar.SECOND) + * instead. + * @see Calendar + * @see #setSeconds(int) + */ + /*public int getSeconds() + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + return cal.get(Calendar.SECOND); + }*/ + + /** + * Sets the seconds to the given value. The other + * fields are only altered as necessary to match + * the same date and time in the new minute. In most + * cases, the other fields won't change at all. However, + * in the case of a leap second, values + * may be adjusted. For example, setting the + * seconds value to 60 or 61 (a leap second) may result + * in the seconds value being reset to 0 and the minutes + * value being incremented by 1, if the current time does + * not contain a leap second. + * + * @param seconds the seconds. + * @deprecated Use Calendar instead of Date, and use + * set(Calendar.SECOND, seconds) instead. + * @see Calendar + * @see #getSeconds() + */ + /*public void setSeconds(int seconds) + { + Calendar cal = Calendar.getInstance(); + cal.setTimeInMillis(time); + cal.set(Calendar.SECOND, seconds); + time = cal.getTimeInMillis(); + }*/ + + /** + * Deserializes a Date object from an + * input stream, setting the time (in milliseconds + * since the epoch) to the long value read from the + * stream. + * + * @param input the input stream. + * @throws IOException if an I/O error occurs in the stream. + * @throws ClassNotFoundException if the class of the + * serialized object could not be found. + */ + /*private void readObject(ObjectInputStream input) + throws IOException, ClassNotFoundException + { + input.defaultReadObject(); + time = input.readLong(); + }*/ + + /** + * Serializes a Date object to an output stream, + * storing the time (in milliseconds since the epoch) as a long + * value in the stream. + * + * @serialdata A long value representing the offset from the epoch + * in milliseconds. This is the same value that is returned by the + * method getTime(). + * @param output the output stream. + * @throws IOException if an I/O error occurs in the stream. + */ + /*private void writeObject(ObjectOutputStream output) + throws IOException + { + output.defaultWriteObject(); + output.writeLong(time); + }*/ + +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/DecimalFormat.java b/Robust/src/ClassLibrary/MGC/gnu/DecimalFormat.java new file mode 100644 index 00000000..57cd7b93 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/DecimalFormat.java @@ -0,0 +1,2284 @@ +/* DecimalFormat.java -- Formats and parses numbers + Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +/* + * This class contains few bits from ICU4J (http://icu.sourceforge.net/), + * Copyright by IBM and others and distributed under the + * distributed under MIT/X. + */ + +//package java.text; + +/*import gnu.java.lang.CPStringBuilder; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import java.util.ArrayList; +import java.util.Currency; +import java.util.Locale; +*/ +/* + * This note is here for historical reasons and because I had not the courage + * to remove it :) + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @date March 4, 1999 + * + * Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.2. + * Note however that the docs are very unclear about how format parsing + * should work. No doubt there are problems here. + */ + +/** + * This class is a concrete implementation of NumberFormat used to format + * decimal numbers. The class can format numbers given a specific locale. + * Generally, to get an instance of DecimalFormat you should call the factory + * methods in the NumberFormat base class. + * + * @author Mario Torre (neugens@limasoftware.net) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class DecimalFormat //extends NumberFormat +{ + /** serialVersionUID for serializartion. */ + private static final long serialVersionUID = 864413376551465018L; + + /** Defines the default number of digits allowed while formatting integers. */ + private static final int DEFAULT_INTEGER_DIGITS = 309; + + /** + * Defines the default number of digits allowed while formatting + * fractions. + */ + private static final int DEFAULT_FRACTION_DIGITS = 340; + + /** + * Locale-independent pattern symbols. + */ + // Happen to be the same as the US symbols. + /*private static final DecimalFormatSymbols nonLocalizedSymbols + = new DecimalFormatSymbols (Locale.US);*/ + + /** + * Defines if parse should return a BigDecimal or not. + */ + private boolean parseBigDecimal; + + /** + * Defines if we have to use the monetary decimal separator or + * the decimal separator while formatting numbers. + */ + private boolean useCurrencySeparator; + + /** Defines if the decimal separator is always shown or not. */ + private boolean decimalSeparatorAlwaysShown; + + /** + * Defines if the decimal separator has to be shown. + * + * This is different then decimalSeparatorAlwaysShown, + * as it defines if the format string contains a decimal separator or no. + */ + private boolean showDecimalSeparator; + + /** + * This field is used to determine if the grouping + * separator is included in the format string or not. + * This is only needed to match the behaviour of the RI. + */ + private boolean groupingSeparatorInPattern; + + /** Defines the size of grouping groups when grouping is used. */ + private byte groupingSize; + + /** + * This is an internal parameter used to keep track of the number + * of digits the form the exponent, when exponential notation is used. + * It is used with exponentRound + */ + private byte minExponentDigits; + + /** This field is used to set the exponent in the engineering notation. */ + private int exponentRound; + + /** Multiplier used in percent style formats. */ + private int multiplier; + + /** Multiplier used in percent style formats. */ + private int negativePatternMultiplier; + + /** The negative prefix. */ + private String negativePrefix; + + /** The negative suffix. */ + private String negativeSuffix; + + /** The positive prefix. */ + private String positivePrefix; + + /** The positive suffix. */ + private String positiveSuffix; + + /** Decimal Format Symbols for the given locale. */ + //private DecimalFormatSymbols symbols; + + /** Determine if we have to use exponential notation or not. */ + private boolean useExponentialNotation; + + /** + * Defines the maximum number of integer digits to show when we use + * the exponential notation. + */ + private int maxIntegerDigitsExponent; + + /** Defines if the format string has a negative prefix or not. */ + private boolean hasNegativePrefix; + + /** Defines if the format string has a fractional pattern or not. */ + private boolean hasFractionalPattern; + + /** Stores a list of attributes for use by formatToCharacterIterator. */ + //private ArrayList attributes = new ArrayList(); + + /** + * Constructs a DecimalFormat which uses the default + * pattern and symbols. + */ + public DecimalFormat() + { + //this ("#,##0.###"); + } + + /** + * Constructs a DecimalFormat which uses the given + * pattern and the default symbols for formatting and parsing. + * + * @param pattern the non-localized pattern to use. + * @throws NullPointerException if any argument is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + public DecimalFormat(String pattern) + { + //this (pattern, new DecimalFormatSymbols()); + } + + /** + * Constructs a DecimalFormat using the given pattern + * and formatting symbols. This construction method is used to give + * complete control over the formatting process. + * + * @param pattern the non-localized pattern to use. + * @param symbols the set of symbols used for parsing and formatting. + * @throws NullPointerException if any argument is null. + * @throws IllegalArgumentException if the pattern is invalid. + */ + /*public DecimalFormat(String pattern, DecimalFormatSymbols symbols) + { + this.symbols = (DecimalFormatSymbols) symbols.clone(); + applyPatternWithSymbols(pattern, nonLocalizedSymbols); + }*/ + + /** + * Apply the given localized patern to the current DecimalFormat object. + * + * @param pattern The localized pattern to apply. + * @throws IllegalArgumentException if the given pattern is invalid. + * @throws NullPointerException if the input pattern is null. + */ + public void applyLocalizedPattern (String pattern) + { + //applyPatternWithSymbols(pattern, this.symbols); + } + + /** + * Apply the given localized pattern to the current DecimalFormat object. + * + * @param pattern The localized pattern to apply. + * @throws IllegalArgumentException if the given pattern is invalid. + * @throws NullPointerException if the input pattern is null. + */ + public void applyPattern(String pattern) + { + //applyPatternWithSymbols(pattern, nonLocalizedSymbols); + } + + public Object clone() + { + /*DecimalFormat c = (DecimalFormat) super.clone(); + c.symbols = (DecimalFormatSymbols) symbols.clone(); + return c;*/ + return null; + } + + /** + * Tests this instance for equality with an arbitrary object. This method + * returns true if: + *
    + *
  • obj is not null;
  • + *
  • obj is an instance of DecimalFormat;
  • + *
  • this instance and obj have the same attributes;
  • + *
+ * + * @param obj the object (null permitted). + * + * @return A boolean. + */ + public boolean equals(Object obj) + { + /*if (! (obj instanceof DecimalFormat)) + return false; + DecimalFormat dup = (DecimalFormat) obj; + return (decimalSeparatorAlwaysShown == dup.decimalSeparatorAlwaysShown + && groupingUsed == dup.groupingUsed + && groupingSeparatorInPattern == dup.groupingSeparatorInPattern + && groupingSize == dup.groupingSize + && multiplier == dup.multiplier + && useExponentialNotation == dup.useExponentialNotation + && minExponentDigits == dup.minExponentDigits + && minimumIntegerDigits == dup.minimumIntegerDigits + && maximumIntegerDigits == dup.maximumIntegerDigits + && minimumFractionDigits == dup.minimumFractionDigits + && maximumFractionDigits == dup.maximumFractionDigits + && parseBigDecimal == dup.parseBigDecimal + && useCurrencySeparator == dup.useCurrencySeparator + && showDecimalSeparator == dup.showDecimalSeparator + && exponentRound == dup.exponentRound + && negativePatternMultiplier == dup.negativePatternMultiplier + && maxIntegerDigitsExponent == dup.maxIntegerDigitsExponent + // XXX: causes equivalent patterns to fail + // && hasNegativePrefix == dup.hasNegativePrefix + && equals(negativePrefix, dup.negativePrefix) + && equals(negativeSuffix, dup.negativeSuffix) + && equals(positivePrefix, dup.positivePrefix) + && equals(positiveSuffix, dup.positiveSuffix) + && symbols.equals(dup.symbols));*/ + return false; + } + + /** + * Returns a hash code for this object. + * + * @return A hash code. + */ + public int hashCode() + { + return toPattern().hashCode(); + } + + public StringBuffer format(long l) { + return null; + } + + /** + * Produce a formatted {@link String} representation of this object. + * The passed object must be of type number. + * + * @param obj The {@link Number} to format. + * @param sbuf The destination String; text will be appended to this String. + * @param pos If used on input can be used to define an alignment + * field. If used on output defines the offsets of the alignment field. + * @return The String representation of this long. + */ + /*public final StringBuffer format(Object obj, StringBuffer sbuf, FieldPosition pos) + { + if (obj instanceof BigInteger) + { + BigDecimal decimal = new BigDecimal((BigInteger) obj); + formatInternal(decimal, true, sbuf, pos); + return sbuf; + } + else if (obj instanceof BigDecimal) + { + formatInternal((BigDecimal) obj, true, sbuf, pos); + return sbuf; + } + + return super.format(obj, sbuf, pos); + }*/ + + /** + * Produce a formatted {@link String} representation of this double. + * + * @param number The double to format. + * @param dest The destination String; text will be appended to this String. + * @param fieldPos If used on input can be used to define an alignment + * field. If used on output defines the offsets of the alignment field. + * @return The String representation of this long. + * @throws NullPointerException if dest or fieldPos are null + */ + /*public StringBuffer format(double number, StringBuffer dest, + FieldPosition fieldPos) + { + // special cases for double: NaN and negative or positive infinity + if (Double.isNaN(number)) + { + // 1. NaN + String nan = symbols.getNaN(); + dest.append(nan); + + // update field position if required + if ((fieldPos.getField() == INTEGER_FIELD || + fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER)) + { + int index = dest.length(); + fieldPos.setBeginIndex(index - nan.length()); + fieldPos.setEndIndex(index); + } + } + else if (Double.isInfinite(number)) + { + // 2. Infinity + if (number < 0) + dest.append(this.negativePrefix); + else + dest.append(this.positivePrefix); + + dest.append(symbols.getInfinity()); + + if (number < 0) + dest.append(this.negativeSuffix); + else + dest.append(this.positiveSuffix); + + if ((fieldPos.getField() == INTEGER_FIELD || + fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER)) + { + fieldPos.setBeginIndex(dest.length()); + fieldPos.setEndIndex(0); + } + } + else + { + // get the number as a BigDecimal + BigDecimal bigDecimal = new BigDecimal(String.valueOf(number)); + formatInternal(bigDecimal, false, dest, fieldPos); + } + + return dest; + }*/ + + /** + * Produce a formatted {@link String} representation of this long. + * + * @param number The long to format. + * @param dest The destination String; text will be appended to this String. + * @param fieldPos If used on input can be used to define an alignment + * field. If used on output defines the offsets of the alignment field. + * @return The String representation of this long. + */ + /*public StringBuffer format(long number, StringBuffer dest, + FieldPosition fieldPos) + { + BigDecimal bigDecimal = new BigDecimal(String.valueOf(number)); + formatInternal(bigDecimal, true, dest, fieldPos); + return dest; + }*/ + + /** + * Return an AttributedCharacterIterator as a result of + * the formatting of the passed {@link Object}. + * + * @return An {@link AttributedCharacterIterator}. + * @throws NullPointerException if value is null. + * @throws IllegalArgumentException if value is not an instance of + * {@link Number}. + */ + /*public AttributedCharacterIterator formatToCharacterIterator(Object value) + { + /* + * This method implementation derives directly from the + * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X. + */ + + /*if (value == null) + throw new NullPointerException("Passed Object is null"); + + if (!(value instanceof Number)) throw new + IllegalArgumentException("Cannot format given Object as a Number"); + + StringBuffer text = new StringBuffer(); + attributes.clear(); + super.format(value, text, new FieldPosition(0)); + + AttributedString as = new AttributedString(text.toString()); + + // add NumberFormat field attributes to the AttributedString + for (int i = 0; i < attributes.size(); i++) + { + FieldPosition pos = (FieldPosition) attributes.get(i); + Format.Field attribute = pos.getFieldAttribute(); + + as.addAttribute(attribute, attribute, pos.getBeginIndex(), + pos.getEndIndex()); + } + + // return the CharacterIterator from AttributedString + return as.getIterator(); + }*/ + + /** + * Returns the currency corresponding to the currency symbol stored + * in the instance of DecimalFormatSymbols used by this + * DecimalFormat. + * + * @return A new instance of Currency if + * the currency code matches a known one, null otherwise. + */ + /*public Currency getCurrency() + { + return symbols.getCurrency(); + }*/ + + /** + * Returns a copy of the symbols used by this instance. + * + * @return A copy of the symbols. + */ + /*public DecimalFormatSymbols getDecimalFormatSymbols() + { + return (DecimalFormatSymbols) symbols.clone(); + }*/ + + /** + * Gets the interval used between a grouping separator and the next. + * For example, a grouping size of 3 means that the number 1234 is + * formatted as 1,234. + * + * The actual character used as grouping separator depends on the + * locale and is defined by {@link DecimalFormatSymbols#getDecimalSeparator()} + * + * @return The interval used between a grouping separator and the next. + */ + public int getGroupingSize() + { + return groupingSize; + } + + /** + * Gets the multiplier used in percent and similar formats. + * + * @return The multiplier used in percent and similar formats. + */ + public int getMultiplier() + { + return multiplier; + } + + /** + * Gets the negative prefix. + * + * @return The negative prefix. + */ + public String getNegativePrefix() + { + return negativePrefix; + } + + /** + * Gets the negative suffix. + * + * @return The negative suffix. + */ + public String getNegativeSuffix() + { + return negativeSuffix; + } + + /** + * Gets the positive prefix. + * + * @return The positive prefix. + */ + public String getPositivePrefix() + { + return positivePrefix; + } + + /** + * Gets the positive suffix. + * + * @return The positive suffix. + */ + public String getPositiveSuffix() + { + return positiveSuffix; + } + + public boolean isDecimalSeparatorAlwaysShown() + { + return decimalSeparatorAlwaysShown; + } + + /** + * Define if parse(java.lang.String, java.text.ParsePosition) + * should return a {@link BigDecimal} or not. + * + * @param newValue + */ + public void setParseBigDecimal(boolean newValue) + { + this.parseBigDecimal = newValue; + } + + /** + * Returns true if + * parse(java.lang.String, java.text.ParsePosition) returns + * a BigDecimal, false otherwise. + * The default return value for this method is false. + * + * @return true if the parse method returns a {@link BigDecimal}, + * false otherwise. + * @since 1.5 + * @see #setParseBigDecimal(boolean) + */ + public boolean isParseBigDecimal() + { + return this.parseBigDecimal; + } + + /** + * This method parses the specified string into a Number. + * + * The parsing starts at pos, which is updated as the parser + * consume characters in the passed string. + * On error, the Position object index is not updated, while + * error position is set appropriately, an null is returned. + * + * @param str The string to parse. + * @param pos The desired ParsePosition. + * + * @return The parsed Number + */ + /*public Number parse(String str, ParsePosition pos) + { + // a special values before anything else + // NaN + if (str.contains(this.symbols.getNaN())) + return Double.valueOf(Double.NaN); + + // this will be our final number + CPStringBuilder number = new CPStringBuilder(); + + // special character + char minus = symbols.getMinusSign(); + + // starting parsing position + int start = pos.getIndex(); + + // validate the string, it have to be in the + // same form as the format string or parsing will fail + String _negativePrefix = (this.negativePrefix.compareTo("") == 0 + ? minus + positivePrefix + : this.negativePrefix); + + // we check both prefixes, because one might be empty. + // We want to pick the longest prefix that matches. + int positiveLen = positivePrefix.length(); + int negativeLen = _negativePrefix.length(); + + boolean isNegative = str.startsWith(_negativePrefix); + boolean isPositive = str.startsWith(positivePrefix); + + if (isPositive && isNegative) + { + // By checking this way, we preserve ambiguity in the case + // where the negative format differs only in suffix. + if (negativeLen > positiveLen) + { + start += _negativePrefix.length(); + isNegative = true; + } + else + { + start += positivePrefix.length(); + isPositive = true; + if (negativeLen < positiveLen) + isNegative = false; + } + } + else if (isNegative) + { + start += _negativePrefix.length(); + isPositive = false; + } + else if (isPositive) + { + start += positivePrefix.length(); + isNegative = false; + } + else + { + pos.setErrorIndex(start); + return null; + } + + // other special characters used by the parser + char decimalSeparator = symbols.getDecimalSeparator(); + char zero = symbols.getZeroDigit(); + char exponent = symbols.getExponential(); + + // stop parsing position in the string + int stop = start + this.maximumIntegerDigits + maximumFractionDigits + 2; + + if (useExponentialNotation) + stop += minExponentDigits + 1; + + boolean inExponent = false; + + // correct the size of the end parsing flag + int len = str.length(); + if (len < stop) stop = len; + char groupingSeparator = symbols.getGroupingSeparator(); + + int i = start; + while (i < stop) + { + char ch = str.charAt(i); + i++; + + if (ch >= zero && ch <= (zero + 9)) + { + number.append(ch); + } + else if (this.parseIntegerOnly) + { + i--; + break; + } + else if (ch == decimalSeparator) + { + number.append('.'); + } + else if (ch == exponent) + { + number.append(ch); + inExponent = !inExponent; + } + else if ((ch == '+' || ch == '-' || ch == minus)) + { + if (inExponent) + number.append(ch); + else + { + i--; + break; + } + } + else + { + if (!groupingUsed || ch != groupingSeparator) + { + i--; + break; + } + } + } + + // 2nd special case: infinity + // XXX: need to be tested + if (str.contains(symbols.getInfinity())) + { + int inf = str.indexOf(symbols.getInfinity()); + pos.setIndex(inf); + + // FIXME: ouch, this is really ugly and lazy code... + if (this.parseBigDecimal) + { + if (isNegative) + return BigDecimal.valueOf(Double.NEGATIVE_INFINITY); + + return BigDecimal.valueOf(Double.POSITIVE_INFINITY); + } + + if (isNegative) + return Double.valueOf(Double.NEGATIVE_INFINITY); + + return Double.valueOf(Double.POSITIVE_INFINITY); + } + + // no number... + if (i == start || number.length() == 0) + { + pos.setErrorIndex(i); + return null; + } + + // now we have to check the suffix, done here after number parsing + // or the index will not be updated correctly... + boolean hasNegativeSuffix = str.endsWith(this.negativeSuffix); + boolean hasPositiveSuffix = str.endsWith(this.positiveSuffix); + boolean positiveEqualsNegative = negativeSuffix.equals(positiveSuffix); + + positiveLen = positiveSuffix.length(); + negativeLen = negativeSuffix.length(); + + if (isNegative && !hasNegativeSuffix) + { + pos.setErrorIndex(i); + return null; + } + else if (hasNegativeSuffix && + !positiveEqualsNegative && + (negativeLen > positiveLen)) + { + isNegative = true; + } + else if (!hasPositiveSuffix) + { + pos.setErrorIndex(i); + return null; + } + + if (isNegative) number.insert(0, '-'); + + pos.setIndex(i); + + // now we handle the return type + BigDecimal bigDecimal = new BigDecimal(number.toString()); + if (this.parseBigDecimal) + return bigDecimal; + + // want integer? + if (this.parseIntegerOnly) + return Long.valueOf(bigDecimal.longValue()); + + // 3th special case -0.0 + if (isNegative && (bigDecimal.compareTo(BigDecimal.ZERO) == 0)) + return Double.valueOf(-0.0); + + try + { + BigDecimal integer + = bigDecimal.setScale(0, BigDecimal.ROUND_UNNECESSARY); + return Long.valueOf(integer.longValue()); + } + catch (ArithmeticException e) + { + return Double.valueOf(bigDecimal.doubleValue()); + } + }*/ + + /** + * Sets the Currency on the + * DecimalFormatSymbols used, which also sets the + * currency symbols on those symbols. + * + * @param currency The new Currency on the + * DecimalFormatSymbols. + */ + /*public void setCurrency(Currency currency) + { + Currency current = symbols.getCurrency(); + if (current != currency) + { + String oldSymbol = symbols.getCurrencySymbol(); + int len = oldSymbol.length(); + symbols.setCurrency(currency); + String newSymbol = symbols.getCurrencySymbol(); + int posPre = positivePrefix.indexOf(oldSymbol); + if (posPre != -1) + positivePrefix = positivePrefix.substring(0, posPre) + + newSymbol + positivePrefix.substring(posPre+len); + int negPre = negativePrefix.indexOf(oldSymbol); + if (negPre != -1) + negativePrefix = negativePrefix.substring(0, negPre) + + newSymbol + negativePrefix.substring(negPre+len); + int posSuf = positiveSuffix.indexOf(oldSymbol); + if (posSuf != -1) + positiveSuffix = positiveSuffix.substring(0, posSuf) + + newSymbol + positiveSuffix.substring(posSuf+len); + int negSuf = negativeSuffix.indexOf(oldSymbol); + if (negSuf != -1) + negativeSuffix = negativeSuffix.substring(0, negSuf) + + newSymbol + negativeSuffix.substring(negSuf+len); + } + }*/ + + /** + * Sets the symbols used by this instance. This method makes a copy of + * the supplied symbols. + * + * @param newSymbols the symbols (null not permitted). + */ + /*public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) + { + symbols = (DecimalFormatSymbols) newSymbols.clone(); + }*/ + + /** + * Define if the decimal separator should be always visible or only + * visible when needed. This method as effect only on integer values. + * Pass true if you want the decimal separator to be + * always shown, false otherwise. + * + * @param newValue true
if you want the decimal separator to be + * always shown, false otherwise. + */ + /*public void setDecimalSeparatorAlwaysShown(boolean newValue) + { + decimalSeparatorAlwaysShown = newValue; + }*/ + + /** + * Sets the number of digits used to group portions of the integer part of + * the number. For example, the number 123456, with a grouping + * size of 3, is rendered 123,456. + * + * @param groupSize The number of digits used while grouping portions + * of the integer part of a number. + */ + public void setGroupingSize(int groupSize) + { + groupingSize = (byte) groupSize; + } + + /** + * Sets the maximum number of digits allowed in the integer + * portion of a number to the specified value. + * The new value will be the choosen as the minimum between + * newvalue and 309. Any value below zero will be + * replaced by zero. + * + * @param newValue The new maximum integer digits value. + */ + /*public void setMaximumIntegerDigits(int newValue) + { + newValue = (newValue > 0) ? newValue : 0; + super.setMaximumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS)); + }*/ + + /** + * Sets the minimum number of digits allowed in the integer + * portion of a number to the specified value. + * The new value will be the choosen as the minimum between + * newvalue and 309. Any value below zero will be + * replaced by zero. + * + * @param newValue The new minimum integer digits value. + */ + /*public void setMinimumIntegerDigits(int newValue) + { + newValue = (newValue > 0) ? newValue : 0; + super.setMinimumIntegerDigits(Math.min(newValue, DEFAULT_INTEGER_DIGITS)); + }*/ + + /** + * Sets the maximum number of digits allowed in the fraction + * portion of a number to the specified value. + * The new value will be the choosen as the minimum between + * newvalue and 309. Any value below zero will be + * replaced by zero. + * + * @param newValue The new maximum fraction digits value. + */ + /*public void setMaximumFractionDigits(int newValue) + { + newValue = (newValue > 0) ? newValue : 0; + super.setMaximumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS)); + }*/ + + /** + * Sets the minimum number of digits allowed in the fraction + * portion of a number to the specified value. + * The new value will be the choosen as the minimum between + * newvalue and 309. Any value below zero will be + * replaced by zero. + * + * @param newValue The new minimum fraction digits value. + */ + /*public void setMinimumFractionDigits(int newValue) + { + newValue = (newValue > 0) ? newValue : 0; + super.setMinimumFractionDigits(Math.min(newValue, DEFAULT_FRACTION_DIGITS)); + }*/ + + /** + * Sets the multiplier for use in percent and similar formats. + * For example, for percent set the multiplier to 100, for permille, set the + * miltiplier to 1000. + * + * @param newValue the new value for multiplier. + */ + public void setMultiplier(int newValue) + { + multiplier = newValue; + } + + /** + * Sets the negative prefix. + * + * @param newValue The new negative prefix. + */ + public void setNegativePrefix(String newValue) + { + negativePrefix = newValue; + } + + /** + * Sets the negative suffix. + * + * @param newValue The new negative suffix. + */ + public void setNegativeSuffix(String newValue) + { + negativeSuffix = newValue; + } + + /** + * Sets the positive prefix. + * + * @param newValue The new positive prefix. + */ + public void setPositivePrefix(String newValue) + { + positivePrefix = newValue; + } + + /** + * Sets the new positive suffix. + * + * @param newValue The new positive suffix. + */ + public void setPositiveSuffix(String newValue) + { + positiveSuffix = newValue; + } + + /** + * This method returns a string with the formatting pattern being used + * by this object. The string is localized. + * + * @return A localized String with the formatting pattern. + * @see #toPattern() + */ + /*public String toLocalizedPattern() + { + return computePattern(this.symbols); + }*/ + + /** + * This method returns a string with the formatting pattern being used + * by this object. The string is not localized. + * + * @return A String with the formatting pattern. + * @see #toLocalizedPattern() + */ + /*public String toPattern() + { + return computePattern(nonLocalizedSymbols); + }*/ + + /* ***** private methods ***** */ + + /** + * This is an shortcut helper method used to test if two given strings are + * equals. + * + * @param s1 The first string to test for equality. + * @param s2 The second string to test for equality. + * @return true if the strings are both null or + * equals. + */ + private boolean equals(String s1, String s2) + { + if (s1 == null || s2 == null) + return s1 == s2; + return s1.equals(s2); + } + + + /* ****** PATTERN ****** */ + + /** + * This helper function creates a string consisting of all the + * characters which can appear in a pattern and must be quoted. + */ + /*private String patternChars (DecimalFormatSymbols syms) + { + CPStringBuilder buf = new CPStringBuilder (); + + buf.append(syms.getDecimalSeparator()); + buf.append(syms.getDigit()); + buf.append(syms.getExponential()); + buf.append(syms.getGroupingSeparator()); + buf.append(syms.getMinusSign()); + buf.append(syms.getPatternSeparator()); + buf.append(syms.getPercent()); + buf.append(syms.getPerMill()); + buf.append(syms.getZeroDigit()); + buf.append('\''); + buf.append('\u00a4'); + + return buf.toString(); + }*/ + + /** + * Quote special characters as defined by patChars in the + * input string. + * + * @param text + * @param patChars + * @return A StringBuffer with special characters quoted. + */ + /*private CPStringBuilder quoteFix(String text, String patChars) + { + CPStringBuilder buf = new CPStringBuilder(); + + int len = text.length(); + char ch; + for (int index = 0; index < len; ++index) + { + ch = text.charAt(index); + if (patChars.indexOf(ch) != -1) + { + buf.append('\''); + buf.append(ch); + if (ch != '\'') buf.append('\''); + } + else + { + buf.append(ch); + } + } + + return buf; + }*/ + + /** + * Returns the format pattern, localized to follow the given + * symbols. + */ + /*private String computePattern(DecimalFormatSymbols symbols) + { + StringBuilder mainPattern = new StringBuilder(); + + // We have to at least emit a zero for the minimum number of + // digits. Past that we need hash marks up to the grouping + // separator (and one beyond). + int _groupingSize = groupingUsed ? groupingSize + 1: groupingSize; + int totalDigits = Math.max(minimumIntegerDigits, _groupingSize); + + // if it is not in exponential notiation, + // we always have a # prebended + if (!useExponentialNotation) mainPattern.append(symbols.getDigit()); + + for (int i = 1; i < totalDigits - minimumIntegerDigits; i++) + mainPattern.append(symbols.getDigit()); + + for (int i = totalDigits - minimumIntegerDigits; i < totalDigits; i++) + mainPattern.append(symbols.getZeroDigit()); + + if (groupingUsed) + { + mainPattern.insert(mainPattern.length() - groupingSize, + symbols.getGroupingSeparator()); + } + + // See if we need decimal info. + if (minimumFractionDigits > 0 || maximumFractionDigits > 0 || + decimalSeparatorAlwaysShown) + { + mainPattern.append(symbols.getDecimalSeparator()); + } + + for (int i = 0; i < minimumFractionDigits; ++i) + mainPattern.append(symbols.getZeroDigit()); + + for (int i = minimumFractionDigits; i < maximumFractionDigits; ++i) + mainPattern.append(symbols.getDigit()); + + if (useExponentialNotation) + { + mainPattern.append(symbols.getExponential()); + + for (int i = 0; i < minExponentDigits; ++i) + mainPattern.append(symbols.getZeroDigit()); + + if (minExponentDigits == 0) + mainPattern.append(symbols.getDigit()); + } + + // save the pattern + String pattern = mainPattern.toString(); + + // so far we have the pattern itself, now we need to add + // the positive and the optional negative prefixes and suffixes + String patternChars = patternChars(symbols); + mainPattern.insert(0, quoteFix(positivePrefix, patternChars)); + mainPattern.append(quoteFix(positiveSuffix, patternChars)); + + if (hasNegativePrefix) + { + mainPattern.append(symbols.getPatternSeparator()); + mainPattern.append(quoteFix(negativePrefix, patternChars)); + mainPattern.append(pattern); + mainPattern.append(quoteFix(negativeSuffix, patternChars)); + } + + // finally, return the pattern string + return mainPattern.toString(); + }*/ + + /* ****** FORMAT PARSING ****** */ + + /** + * Scan the input string and define a pattern suitable for use + * with this decimal format. + * + * @param pattern + * @param symbols + */ + /*private void applyPatternWithSymbols(String pattern, + DecimalFormatSymbols symbols) + { + // The pattern string is described by a BNF diagram. + // we could use a recursive parser to read and prepare + // the string, but this would be too slow and resource + // intensive, while this code is quite critical as it is + // called always when the class is instantiated and every + // time a new pattern is given. + // Our strategy is to divide the string into section as given by + // the BNF diagram, iterating through the string and setting up + // the parameters we need for formatting (which is basicly what + // a descendent recursive parser would do - but without recursion). + // I'm sure that there are smarter methods to do this. + + // Restore default values. Most of these will be overwritten + // but we want to be sure that nothing is left out. + setDefaultValues(); + + int len = pattern.length(); + if (len == 0) + { + // this is another special case... + this.minimumIntegerDigits = 1; + this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS; + this.minimumFractionDigits = 0; + this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS; + + // FIXME: ...and these values may not be valid in all locales + this.minExponentDigits = 0; + this.showDecimalSeparator = true; + this.groupingUsed = true; + this.groupingSize = 3; + + return; + } + + int start = scanFix(pattern, symbols, 0, true); + if (start < len) start = scanNumberInteger(pattern, symbols, start); + if (start < len) + { + start = scanFractionalPortion(pattern, symbols, start); + } + else + { + // special case, pattern that ends here does not have a fractional + // portion + this.minimumFractionDigits = 0; + this.maximumFractionDigits = 0; + //this.decimalSeparatorAlwaysShown = false; + //this.showDecimalSeparator = false; + } + + // XXX: this fixes a compatibility test with the RI. + // If new uses cases fail, try removing this line first. + //if (!this.hasIntegerPattern && !this.hasFractionalPattern) + // throw new IllegalArgumentException("No valid pattern found!"); + + if (start < len) start = scanExponent(pattern, symbols, start); + if (start < len) start = scanFix(pattern, symbols, start, false); + if (start < len) scanNegativePattern(pattern, symbols, start); + + if (useExponentialNotation && + (maxIntegerDigitsExponent > minimumIntegerDigits) && + (maxIntegerDigitsExponent > 1)) + { + minimumIntegerDigits = 1; + exponentRound = maxIntegerDigitsExponent; + } + + if (useExponentialNotation) + maximumIntegerDigits = maxIntegerDigitsExponent; + + if (!this.hasFractionalPattern && this.showDecimalSeparator == true) + { + this.decimalSeparatorAlwaysShown = true; + } + }*/ + + /** + * Scans for the prefix or suffix portion of the pattern string. + * This method handles the positive subpattern of the pattern string. + * + * @param pattern The pattern string to parse. + * @return The position in the pattern string where parsing ended. + */ + /*private int scanFix(String pattern, DecimalFormatSymbols sourceSymbols, + int start, boolean prefix) + { + CPStringBuilder buffer = new CPStringBuilder(); + + // the number portion is always delimited by one of those + // characters + char decimalSeparator = sourceSymbols.getDecimalSeparator(); + char patternSeparator = sourceSymbols.getPatternSeparator(); + char groupingSeparator = sourceSymbols.getGroupingSeparator(); + char digit = sourceSymbols.getDigit(); + char zero = sourceSymbols.getZeroDigit(); + char minus = sourceSymbols.getMinusSign(); + + // other special characters, cached here to avoid method calls later + char percent = sourceSymbols.getPercent(); + char permille = sourceSymbols.getPerMill(); + + String currencySymbol = this.symbols.getCurrencySymbol(); + + boolean quote = false; + + char ch = pattern.charAt(start); + if (ch == patternSeparator) + { + // negative subpattern + this.hasNegativePrefix = true; + ++start; + return start; + } + + int len = pattern.length(); + int i; + for (i = start; i < len; i++) + { + ch = pattern.charAt(i); + + // we are entering into the negative subpattern + if (!quote && ch == patternSeparator) + { + if (this.hasNegativePrefix) + { + throw new IllegalArgumentException("Invalid pattern found: " + + start); + } + + this.hasNegativePrefix = true; + ++i; + break; + } + + // this means we are inside the number portion + if (!quote && + (ch == minus || ch == digit || ch == zero || + ch == groupingSeparator)) + break; + + if (!quote && ch == decimalSeparator) + { + this.showDecimalSeparator = true; + break; + } + else if (quote && ch != '\'') + { + buffer.append(ch); + continue; + } + + if (ch == '\u00A4') + { + // CURRENCY + currencySymbol = this.symbols.getCurrencySymbol(); + + // if \u00A4 is doubled, we use the international currency symbol + if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4') + { + currencySymbol = this.symbols.getInternationalCurrencySymbol(); + i++; + } + + this.useCurrencySeparator = true; + buffer.append(currencySymbol); + } + else if (ch == percent) + { + // PERCENT + this.multiplier = 100; + buffer.append(this.symbols.getPercent()); + } + else if (ch == permille) + { + // PERMILLE + this.multiplier = 1000; + buffer.append(this.symbols.getPerMill()); + } + else if (ch == '\'') + { + // QUOTE + if ((i + 1) < len && pattern.charAt(i + 1) == '\'') + { + // we need to add ' to the buffer + buffer.append(ch); + i++; + } + else + { + quote = !quote; + continue; + } + } + else + { + buffer.append(ch); + } + } + + if (prefix) + { + this.positivePrefix = buffer.toString(); + this.negativePrefix = minus + "" + positivePrefix; + } + else + { + this.positiveSuffix = buffer.toString(); + } + + return i; + }*/ + + /** + * Scan the given string for number patterns, starting + * from start. + * This method searches the integer part of the pattern only. + * + * @param pattern The pattern string to parse. + * @param start The starting parse position in the string. + * @return The position in the pattern string where parsing ended, + * counted from the beginning of the string (that is, 0). + */ + /*private int scanNumberInteger(String pattern, DecimalFormatSymbols symbols, + int start) + { + char digit = symbols.getDigit(); + char zero = symbols.getZeroDigit(); + char groupingSeparator = symbols.getGroupingSeparator(); + char decimalSeparator = symbols.getDecimalSeparator(); + char exponent = symbols.getExponential(); + char patternSeparator = symbols.getPatternSeparator(); + + // count the number of zeroes in the pattern + // this number defines the minum digits in the integer portion + int zeros = 0; + + // count the number of digits used in grouping + int _groupingSize = 0; + + this.maxIntegerDigitsExponent = 0; + + boolean intPartTouched = false; + + char ch; + int len = pattern.length(); + int i; + for (i = start; i < len; i++) + { + ch = pattern.charAt(i); + + // break on decimal separator or exponent or pattern separator + if (ch == decimalSeparator || ch == exponent) + break; + + if (this.hasNegativePrefix && ch == patternSeparator) + throw new IllegalArgumentException("Invalid pattern found: " + + start); + + if (ch == digit) + { + // in our implementation we could relax this strict + // requirement, but this is used to keep compatibility with + // the RI + if (zeros > 0) throw new + IllegalArgumentException("digit mark following zero in " + + "positive subpattern, not allowed. Position: " + i); + + _groupingSize++; + intPartTouched = true; + this.maxIntegerDigitsExponent++; + } + else if (ch == zero) + { + zeros++; + _groupingSize++; + this.maxIntegerDigitsExponent++; + } + else if (ch == groupingSeparator) + { + this.groupingSeparatorInPattern = true; + this.groupingUsed = true; + _groupingSize = 0; + } + else + { + // any other character not listed above + // means we are in the suffix portion + break; + } + } + + if (groupingSeparatorInPattern) this.groupingSize = (byte) _groupingSize; + this.minimumIntegerDigits = zeros; + + // XXX: compatibility code with the RI: the number of minimum integer + // digits is at least one when maximumIntegerDigits is more than zero + if (intPartTouched && this.maximumIntegerDigits > 0 && + this.minimumIntegerDigits == 0) + this.minimumIntegerDigits = 1; + + return i; + }*/ + + /** + * Scan the given string for number patterns, starting + * from start. + * This method searches the fractional part of the pattern only. + * + * @param pattern The pattern string to parse. + * @param start The starting parse position in the string. + * @return The position in the pattern string where parsing ended, + * counted from the beginning of the string (that is, 0). + */ + /*private int scanFractionalPortion(String pattern, + DecimalFormatSymbols symbols, + int start) + { + char digit = symbols.getDigit(); + char zero = symbols.getZeroDigit(); + char groupingSeparator = symbols.getGroupingSeparator(); + char decimalSeparator = symbols.getDecimalSeparator(); + char exponent = symbols.getExponential(); + char patternSeparator = symbols.getPatternSeparator(); + + // first character needs to be '.' otherwise we are not parsing the + // fractional portion + char ch = pattern.charAt(start); + if (ch != decimalSeparator) + { + this.minimumFractionDigits = 0; + this.maximumFractionDigits = 0; + return start; + } + + ++start; + + this.hasFractionalPattern = true; + + this.minimumFractionDigits = 0; + int digits = 0; + + int len = pattern.length(); + int i; + for (i = start; i < len; i++) + { + ch = pattern.charAt(i); + + // we hit the exponential or negative subpattern + if (ch == exponent || ch == patternSeparator) + break; + + // pattern error + if (ch == groupingSeparator || ch == decimalSeparator) throw new + IllegalArgumentException("unexpected character '" + ch + "' " + + "in fractional subpattern. Position: " + i); + + if (ch == digit) + { + digits++; + } + else if (ch == zero) + { + if (digits > 0) throw new + IllegalArgumentException("digit mark following zero in " + + "positive subpattern, not allowed. Position: " + i); + + this.minimumFractionDigits++; + } + else + { + // we are in the suffix section of pattern + break; + } + } + + if (i == start) this.hasFractionalPattern = false; + + this.maximumFractionDigits = this.minimumFractionDigits + digits; + this.showDecimalSeparator = true; + + return i; + }*/ + + /** + * Scan the given string for number patterns, starting + * from start. + * This method searches the expoential part of the pattern only. + * + * @param pattern The pattern string to parse. + * @param start The starting parse position in the string. + * @return The position in the pattern string where parsing ended, + * counted from the beginning of the string (that is, 0). + */ + /*private int scanExponent(String pattern, DecimalFormatSymbols symbols, + int start) + { + char digit = symbols.getDigit(); + char zero = symbols.getZeroDigit(); + char groupingSeparator = symbols.getGroupingSeparator(); + char decimalSeparator = symbols.getDecimalSeparator(); + char exponent = symbols.getExponential(); + + char ch = pattern.charAt(start); + + if (ch == decimalSeparator) + { + // ignore dots + ++start; + } + + if (ch != exponent) + { + this.useExponentialNotation = false; + return start; + } + + ++start; + + this.minExponentDigits = 0; + + int len = pattern.length(); + int i; + for (i = start; i < len; i++) + { + ch = pattern.charAt(i); + + if (ch == groupingSeparator || ch == decimalSeparator || + ch == digit || ch == exponent) throw new + IllegalArgumentException("unexpected character '" + ch + "' " + + "in exponential subpattern. Position: " + i); + + if (ch == zero) + { + this.minExponentDigits++; + } + else + { + // any character other than zero is an exit point + break; + } + } + + this.useExponentialNotation = true; + + return i; + }*/ + + /** + * Scan the given string for number patterns, starting + * from start. + * This method searches the negative part of the pattern only and scan + * throught the end of the string. + * + * @param pattern The pattern string to parse. + * @param start The starting parse position in the string. + */ + /*private void scanNegativePattern(String pattern, + DecimalFormatSymbols sourceSymbols, + int start) + { + StringBuilder buffer = new StringBuilder(); + + // the number portion is always delimited by one of those + // characters + char decimalSeparator = sourceSymbols.getDecimalSeparator(); + char patternSeparator = sourceSymbols.getPatternSeparator(); + char groupingSeparator = sourceSymbols.getGroupingSeparator(); + char digit = sourceSymbols.getDigit(); + char zero = sourceSymbols.getZeroDigit(); + char minus = sourceSymbols.getMinusSign(); + + // other special charcaters, cached here to avoid method calls later + char percent = sourceSymbols.getPercent(); + char permille = sourceSymbols.getPerMill(); + + String CURRENCY_SYMBOL = this.symbols.getCurrencySymbol(); + String currencySymbol = CURRENCY_SYMBOL; + + boolean quote = false; + boolean prefixDone = false; + + int len = pattern.length(); + if (len > 0) this.hasNegativePrefix = true; + + char ch = pattern.charAt(start); + if (ch == patternSeparator) + { + // no pattern separator in the negative pattern + if ((start + 1) > len) throw new + IllegalArgumentException("unexpected character '" + ch + "' " + + "in negative subpattern."); + start++; + } + + int i; + for (i = start; i < len; i++) + { + ch = pattern.charAt(i); + + // this means we are inside the number portion + if (!quote && + (ch == digit || ch == zero || ch == decimalSeparator || + ch == patternSeparator || ch == groupingSeparator)) + { + if (!prefixDone) + { + this.negativePrefix = buffer.toString(); + buffer.delete(0, buffer.length()); + prefixDone = true; + } + } + else if (ch == minus) + { + buffer.append(this.symbols.getMinusSign()); + } + else if (quote && ch != '\'') + { + buffer.append(ch); + } + else if (ch == '\u00A4') + { + // CURRENCY + currencySymbol = CURRENCY_SYMBOL; + + // if \u00A4 is doubled, we use the international currency symbol + if ((i + 1) < len && pattern.charAt(i + 1) == '\u00A4') + { + currencySymbol = this.symbols.getInternationalCurrencySymbol(); + i = i + 2; + } + + // FIXME: not sure about this, the specs says that we only have to + // change prefix and suffix, so leave it as commented + // unless in case of bug report/errors + //this.useCurrencySeparator = true; + + buffer.append(currencySymbol); + } + else if (ch == percent) + { + // PERCENT + this.negativePatternMultiplier = 100; + buffer.append(this.symbols.getPercent()); + } + else if (ch == permille) + { + // PERMILLE + this.negativePatternMultiplier = 1000; + buffer.append(this.symbols.getPerMill()); + } + else if (ch == '\'') + { + // QUOTE + if ((i + 1) < len && pattern.charAt(i + 1) == '\'') + { + // we need to add ' to the buffer + buffer.append(ch); + i++; + } + else + { + quote = !quote; + } + } + else if (ch == patternSeparator) + { + // no pattern separator in the negative pattern + throw new IllegalArgumentException("unexpected character '" + ch + + "' in negative subpattern."); + } + else + { + buffer.append(ch); + } + } + + if (prefixDone) + this.negativeSuffix = buffer.toString(); + else + this.negativePrefix = buffer.toString(); + }*/ + + /* ****** FORMATTING ****** */ + + /** + * Handles the real formatting. + * + * We use a BigDecimal to format the number without precision loss. + * All the rounding is done by methods in BigDecimal. + * The isLong parameter is used to determine if we are + * formatting a long or BigInteger. In this case, we avoid to format + * the fractional part of the number (unless specified otherwise in the + * format string) that would consist only of a 0 digit. + * + * @param number A BigDecimal representation fo the input number. + * @param dest The destination buffer. + * @param isLong A boolean that indicates if this BigDecimal is a real + * decimal or an integer. + * @param fieldPos Use to keep track of the formatting position. + */ + /*private void formatInternal(BigDecimal number, boolean isLong, + StringBuffer dest, FieldPosition fieldPos) + { + // The specs says that fieldPos should not be null, and that we + // should throw a NPE, but it seems that in few classes that + // reference this one, fieldPos is set to null. + // This is even defined in the javadoc, see for example MessageFormat. + // I think the best here is to check for fieldPos and build one if it is + // null. If it cause harms or regressions, just remove this line and + // fix the classes in the point of call, insted. + if (fieldPos == null) fieldPos = new FieldPosition(0); + + int _multiplier = this.multiplier; + + // used to track attribute starting position for each attribute + int attributeStart = -1; + + // now get the sign this will be used by the special case Inifinity + // and by the normal cases. + boolean isNegative = (number.signum() < 0) ? true : false; + if (isNegative) + { + attributeStart = dest.length(); + + // append the negative prefix to the string + dest.append(negativePrefix); + + // once got the negative prefix, we can use + // the absolute value. + number = number.abs(); + + _multiplier = negativePatternMultiplier; + + addAttribute(Field.SIGN, attributeStart, dest.length()); + } + else + { + // not negative, use the positive prefix + dest.append(positivePrefix); + } + + // these are used ot update the field position + int beginIndexInt = dest.length(); + int endIndexInt = 0; + int beginIndexFract = 0; + int endIndexFract = 0; + + // compute the multiplier to use with percent and similar + number = number.multiply(BigDecimal.valueOf(_multiplier)); + + // XXX: special case, not sure if it belongs here or if it is + // correct at all. There may be other special cases as well + // these should be handled in the format string parser. + if (this.maximumIntegerDigits == 0 && this.maximumFractionDigits == 0) + { + number = BigDecimal.ZERO; + this.maximumIntegerDigits = 1; + this.minimumIntegerDigits = 1; + } + + // get the absolute number + number = number.abs(); + + // the scaling to use while formatting this number + int scale = this.maximumFractionDigits; + + // this is the actual number we will use + // it is corrected later on to handle exponential + // notation, if needed + long exponent = 0; + + // are we using exponential notation? + if (this.useExponentialNotation) + { + exponent = getExponent(number); + number = number.movePointLeft((int) exponent); + + // FIXME: this makes the test ##.###E0 to pass, + // but all all the other tests to fail... + // this should be really something like + // min + max - what is already shown... + //scale = this.minimumIntegerDigits + this.maximumFractionDigits; + } + + // round the number to the nearest neighbor + number = number.setScale(scale, BigDecimal.ROUND_HALF_EVEN); + + // now get the integer and fractional part of the string + // that will be processed later + String plain = number.toPlainString(); + + String intPart = null; + String fractPart = null; + + // remove - from the integer part, this is needed as + // the Narrowing Primitive Conversions algorithm used may loose + // information about the sign + int minusIndex = plain.lastIndexOf('-', 0); + if (minusIndex > -1) plain = plain.substring(minusIndex + 1); + + // strip the decimal portion + int dot = plain.indexOf('.'); + if (dot > -1) + { + intPart = plain.substring(0, dot); + dot++; + + if (useExponentialNotation) + fractPart = plain.substring(dot, dot + scale); + else + fractPart = plain.substring(dot); + } + else + { + intPart = plain; + } + + // used in various places later on + int intPartLen = intPart.length(); + endIndexInt = intPartLen; + + // if the number of digits in our intPart is not greater than the + // minimum we have to display, we append zero to the destination + // buffer before adding the integer portion of the number. + int zeroes = minimumIntegerDigits - intPartLen; + if (zeroes > 0) + { + attributeStart = Math.max(dest.length() - 1, 0); + appendZero(dest, zeroes, minimumIntegerDigits); + } + + if (this.useExponentialNotation) + { + // For exponential numbers, the significant in mantissa are + // the sum of the minimum integer and maximum fraction + // digits, and does not take into account the maximun integer + // digits to display. + + if (attributeStart < 0) + attributeStart = Math.max(dest.length() - 1, 0); + appendDigit(intPart, dest, this.groupingUsed); + } + else + { + // non exponential notation + intPartLen = intPart.length(); + int canary = Math.min(intPartLen, this.maximumIntegerDigits); + + // remove from the string the number in excess + // use only latest digits + intPart = intPart.substring(intPartLen - canary); + endIndexInt = intPart.length() + 1; + + // append it + if (maximumIntegerDigits > 0 && + !(this.minimumIntegerDigits == 0 && + intPart.compareTo(String.valueOf(symbols.getZeroDigit())) == 0)) + { + if (attributeStart < 0) + attributeStart = Math.max(dest.length() - 1, 0); + appendDigit(intPart, dest, this.groupingUsed); + } + } + + // add the INTEGER attribute + addAttribute(Field.INTEGER, attributeStart, dest.length()); + + // ...update field position, if needed, and return... + if ((fieldPos.getField() == INTEGER_FIELD || + fieldPos.getFieldAttribute() == NumberFormat.Field.INTEGER)) + { + fieldPos.setBeginIndex(beginIndexInt); + fieldPos.setEndIndex(endIndexInt); + } + + handleFractionalPart(dest, fractPart, fieldPos, isLong); + + // and the exponent + if (this.useExponentialNotation) + { + attributeStart = dest.length(); + + dest.append(symbols.getExponential()); + + addAttribute(Field.EXPONENT_SYMBOL, attributeStart, dest.length()); + attributeStart = dest.length(); + + if (exponent < 0) + { + dest.append(symbols.getMinusSign()); + exponent = -exponent; + + addAttribute(Field.EXPONENT_SIGN, attributeStart, dest.length()); + } + + attributeStart = dest.length(); + + String exponentString = String.valueOf(exponent); + int exponentLength = exponentString.length(); + + for (int i = 0; i < minExponentDigits - exponentLength; i++) + dest.append(symbols.getZeroDigit()); + + for (int i = 0; i < exponentLength; ++i) + dest.append(exponentString.charAt(i)); + + addAttribute(Field.EXPONENT, attributeStart, dest.length()); + } + + // now include the suffixes... + if (isNegative) + { + dest.append(negativeSuffix); + } + else + { + dest.append(positiveSuffix); + } + }*/ + + /** + * Add to the input buffer the result of formatting the fractional + * portion of the number. + * + * @param dest + * @param fractPart + * @param fieldPos + * @param isLong + */ + /*private void handleFractionalPart(StringBuffer dest, String fractPart, + FieldPosition fieldPos, boolean isLong) + { + int dotStart = 0; + int dotEnd = 0; + boolean addDecimal = false; + + if (this.decimalSeparatorAlwaysShown || + ((!isLong || this.useExponentialNotation) && + this.showDecimalSeparator && this.maximumFractionDigits > 0) || + this.minimumFractionDigits > 0) + { + dotStart = dest.length(); + + if (this.useCurrencySeparator) + dest.append(symbols.getMonetaryDecimalSeparator()); + else + dest.append(symbols.getDecimalSeparator()); + + dotEnd = dest.length(); + addDecimal = true; + } + + // now handle the fraction portion of the number + int fractStart = 0; + int fractEnd = 0; + boolean addFractional = false; + + if ((!isLong || this.useExponentialNotation) + && this.maximumFractionDigits > 0 + || this.minimumFractionDigits > 0) + { + fractStart = dest.length(); + fractEnd = fractStart; + + int digits = this.minimumFractionDigits; + + if (this.useExponentialNotation) + { + digits = (this.minimumIntegerDigits + this.minimumFractionDigits) + - dest.length(); + if (digits < 0) digits = 0; + } + + fractPart = adjustTrailingZeros(fractPart, digits); + + // FIXME: this code must be improved + // now check if the factional part is just 0, in this case + // we need to remove the '.' unless requested + boolean allZeros = true; + char fracts[] = fractPart.toCharArray(); + for (int i = 0; i < fracts.length; i++) + { + if (fracts[i] != '0') + allZeros = false; + } + + if (!allZeros || (minimumFractionDigits > 0)) + { + appendDigit(fractPart, dest, false); + fractEnd = dest.length(); + + addDecimal = true; + addFractional = true; + } + else if (!this.decimalSeparatorAlwaysShown) + { + dest.deleteCharAt(dest.length() - 1); + addDecimal = false; + } + else + { + fractEnd = dest.length(); + addFractional = true; + } + } + + if (addDecimal) + addAttribute(Field.DECIMAL_SEPARATOR, dotStart, dotEnd); + + if (addFractional) + addAttribute(Field.FRACTION, fractStart, fractEnd); + + if ((fieldPos.getField() == FRACTION_FIELD || + fieldPos.getFieldAttribute() == NumberFormat.Field.FRACTION)) + { + fieldPos.setBeginIndex(fractStart); + fieldPos.setEndIndex(fractEnd); + } + }*/ + + /** + * Append to destthe give number of zeros. + * Grouping is added if needed. + * The integer totalDigitCount defines the total number of digits + * of the number to which we are appending zeroes. + */ + private void appendZero(StringBuffer dest, int zeroes, int totalDigitCount) + { + char ch = symbols.getZeroDigit(); + char gSeparator = symbols.getGroupingSeparator(); + + int i = 0; + int gPos = totalDigitCount; + for (i = 0; i < zeroes; i++, gPos--) + { + if (this.groupingSeparatorInPattern && + (this.groupingUsed && this.groupingSize != 0) && + (gPos % groupingSize == 0 && i > 0)) + dest.append(gSeparator); + + dest.append(ch); + } + + // special case, that requires adding an additional separator + if (this.groupingSeparatorInPattern && + (this.groupingUsed && this.groupingSize != 0) && + (gPos % groupingSize == 0)) + dest.append(gSeparator); + } + + /** + * Append src to dest. + * + * Grouping is added if groupingUsed is set + * to true. + */ + private void appendDigit(String src, StringBuffer dest, + boolean groupingUsed) + { + int zero = symbols.getZeroDigit() - '0'; + + int ch; + char gSeparator = symbols.getGroupingSeparator(); + + int len = src.length(); + for (int i = 0, gPos = len; i < len; i++, gPos--) + { + ch = src.charAt(i); + if (groupingUsed && this.groupingSize != 0 && + gPos % groupingSize == 0 && i > 0) + dest.append(gSeparator); + + dest.append((char) (zero + ch)); + } + } + + /** + * Calculate the exponent to use if eponential notation is used. + * The exponent is calculated as a power of ten. + * number should be positive, if is zero, or less than zero, + * zero is returned. + */ + private long getExponent(BigDecimal number) + { + long exponent = 0; + + if (number.signum() > 0) + { + double _number = number.doubleValue(); + exponent = (long) Math.floor (Math.log10(_number)); + + // get the right value for the exponent + exponent = exponent - (exponent % this.exponentRound); + + // if the minimumIntegerDigits is more than zero + // we display minimumIntegerDigits of digits. + // so, for example, if minimumIntegerDigits == 2 + // and the actual number is 0.123 it will be + // formatted as 12.3E-2 + // this means that the exponent have to be shifted + // to the correct value. + if (minimumIntegerDigits > 0) + exponent -= minimumIntegerDigits - 1; + } + + return exponent; + } + + /** + * Remove contiguos zeros from the end of the src string, + * if src contains more than minimumDigits digits. + * if src contains less that minimumDigits, + * then append zeros to the string. + * + * Only the first block of zero digits is removed from the string + * and only if they fall in the src.length - minimumDigits + * portion of the string. + * + * @param src The string with the correct number of zeros. + */ + /*private String adjustTrailingZeros(String src, int minimumDigits) + { + int len = src.length(); + String result; + + // remove all trailing zero + if (len > minimumDigits) + { + int zeros = 0; + for (int i = len - 1; i > minimumDigits; i--) + { + if (src.charAt(i) == '0') + ++zeros; + else + break; + } + result = src.substring(0, len - zeros); + } + else + { + char zero = symbols.getZeroDigit(); + CPStringBuilder _result = new CPStringBuilder(src); + for (int i = len; i < minimumDigits; i++) + { + _result.append(zero); + } + result = _result.toString(); + } + + return result; + }*/ + + /** + * Adds an attribute to the attributes list. + * + * @param field + * @param begin + * @param end + */ + /*private void addAttribute(Field field, int begin, int end) + { + /* + * This method and its implementation derives directly from the + * ICU4J (http://icu.sourceforge.net/) library, distributed under MIT/X. + */ + + /*FieldPosition pos = new FieldPosition(field); + pos.setBeginIndex(begin); + pos.setEndIndex(end); + attributes.add(pos); + }*/ + + /** + * Sets the default values for the various properties in this DecimaFormat. + */ + private void setDefaultValues() + { + // Maybe we should add these values to the message bundle and take + // the most appropriate for them for any locale. + // Anyway, these seem to be good values for a default in most languages. + // Note that most of these will change based on the format string. + + this.negativePrefix = String.valueOf(symbols.getMinusSign()); + this.negativeSuffix = ""; + this.positivePrefix = ""; + this.positiveSuffix = ""; + + this.multiplier = 1; + this.negativePatternMultiplier = 1; + this.exponentRound = 1; + + this.hasNegativePrefix = false; + + this.minimumIntegerDigits = 1; + this.maximumIntegerDigits = DEFAULT_INTEGER_DIGITS; + this.minimumFractionDigits = 0; + this.maximumFractionDigits = DEFAULT_FRACTION_DIGITS; + this.minExponentDigits = 0; + + this.groupingSize = 0; + + this.decimalSeparatorAlwaysShown = false; + this.showDecimalSeparator = false; + this.useExponentialNotation = false; + this.groupingUsed = false; + this.groupingSeparatorInPattern = false; + + this.useCurrencySeparator = false; + + this.hasFractionalPattern = false; + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/Exception.java b/Robust/src/ClassLibrary/MGC/gnu/Exception.java new file mode 100644 index 00000000..42f7c640 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Exception.java @@ -0,0 +1,104 @@ +/* Exception.java -- generic exception thrown to indicate an exceptional + condition has occurred. + Copyright (C) 1998, 1999, 2001, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +/** + * The root class of all exceptions worth catching in a program. This + * includes the special category of RuntimeException, which + * does not need to be declared in a throws clause. Exceptions can be used + * to represent almost any exceptional behavior, such as programming errors, + * mouse movements, keyboard clicking, etc. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class Exception extends Throwable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -3387516993124229948L; + + /** + * Create an exception without a message. The cause remains uninitialized. + * + * @see #initCause(Throwable) + */ + public Exception() + { + } + + /** + * Create an exception with a message. The cause remains uninitialized. + * + * @param s the message + * @see #initCause(Throwable) + */ + public Exception(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message string + * @param cause the cause of this error + * @since 1.4 + */ + public Exception(String s, Throwable cause) + { + super(s, cause); + } + + /** + * Create an exception with a given cause, and a message of + * cause == null ? null : cause.toString(). + * + * @param cause the cause of this exception + * @since 1.4 + */ + public Exception(Throwable cause) + { + super(cause); + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/FileDescriptor.java b/Robust/src/ClassLibrary/MGC/gnu/FileDescriptor.java new file mode 100644 index 00000000..7b9c146b --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/FileDescriptor.java @@ -0,0 +1,146 @@ +/* FileDescriptor.java -- Opaque file handle class + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/*import gnu.java.nio.FileChannelImpl; + +import java.nio.channels.ByteChannel; +import java.nio.channels.FileChannel; +*/ +/** + * This class represents an opaque file handle as a Java class. It should + * be used only to pass to other methods that expect an object of this + * type. No system specific information can be obtained from this object. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @date September 24, 1998 + */ +public final class FileDescriptor +{ + /** + * A FileDescriptor representing the system standard input + * stream. This will usually be accessed through the + * System.invariable. + */ + public static final FileDescriptor in + = new FileDescriptor ("System.in"/*FileChannelImpl.in*/); + + /** + * A FileDescriptor representing the system standard output + * stream. This will usually be accessed through the + * System.outvariable. + */ + public static final FileDescriptor out + = new FileDescriptor ("System.out"/*FileChannelImpl.out*/); + + /** + * A FileDescriptor representing the system standard error + * stream. This will usually be accessed through the + * System.errvariable. + */ + public static final FileDescriptor err + = new FileDescriptor ("System.err"/*FileChannelImpl.err*/); + + //final ByteChannel channel; + final String channel; + + /** + * This method is used to initialize an invalid FileDescriptor object. + */ + public FileDescriptor() + { + channel = null; + } + + /** + * This method is used to initialize a FileDescriptor object. + */ + /*FileDescriptor(ByteChannel channel) + { + this.channel = channel; + }*/ + + FileDescriptor(String channel) + { + this.channel = channel; + } + + + /** + * This method forces all data that has not yet been physically written to + * the underlying storage medium associated with this + * FileDescriptor + * to be written out. This method will not return until all data has + * been fully written to the underlying device. If the device does not + * support this functionality or if an error occurs, then an exception + * will be thrown. + */ + /*public void sync () throws SyncFailedException + { + if (channel instanceof FileChannel) + { + try + { + ((FileChannel) channel).force(true); + } + catch (IOException ex) + { + if (ex instanceof SyncFailedException) + throw (SyncFailedException) ex; + else + throw new SyncFailedException(ex.toString()); + } + } + }*/ + + /** + * This methods tests whether or not this object represents a valid open + * native file handle. + * + * @return true if this object represents a valid + * native file handle, false otherwise + */ + /*public boolean valid () + { + ByteChannel c = channel; + return (c != null) && (c.isOpen()); + }*/ +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/FilterOutputStream.java b/Robust/src/ClassLibrary/MGC/gnu/FilterOutputStream.java new file mode 100644 index 00000000..dd5ad6e8 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/FilterOutputStream.java @@ -0,0 +1,150 @@ +/* FilterOutputStream.java -- Parent class for output streams that filter + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.1. + */ + +/** + * This class is the common superclass of output stream classes that + * filter the output they write. These classes typically transform the + * data in some way prior to writing it out to another underlying + * OutputStream. This class simply overrides all the + * methods in OutputStream to redirect them to the + * underlying stream. Subclasses provide actual filtering. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class FilterOutputStream extends OutputStream +{ + /** + * This is the subordinate OutputStream that this class + * redirects its method calls to. + */ + protected OutputStream out; + + /** + * This method initializes an instance of FilterOutputStream + * to write to the specified subordinate OutputStream. + * + * @param out The OutputStream to write to + */ + public FilterOutputStream(OutputStream out) + { + this.out = out; + } + + /** + * This method closes the underlying OutputStream. Any + * further attempts to write to this stream may throw an exception. + * + * @exception IOException If an error occurs + */ + public void close() //throws IOException + { + flush(); + out.close(); + } + + /** + * This method attempt to flush all buffered output to be written to the + * underlying output sink. + * + * @exception IOException If an error occurs + */ + public void flush() //throws IOException + { + out.flush(); + } + + /** + * This method writes a single byte of output to the underlying + * OutputStream. + * + * @param b The byte to write, passed as an int. + * + * @exception IOException If an error occurs + */ + public void write(int b) //throws IOException + { + out.write(b); + } + + /** + * This method writes all the bytes in the specified array to the underlying + * OutputStream. It does this by calling the three parameter + * version of this method - write(byte[], int, int) in this + * class instead of writing to the underlying OutputStream + * directly. This allows most subclasses to avoid overriding this method. + * + * @param buf The byte array to write bytes from + * + * @exception IOException If an error occurs + */ + public void write(byte[] buf) //throws IOException + { + // Don't do checking here, per Java Lang Spec. + write(buf, 0, buf.length); + } + + /** + * This method calls the write(int) method len + * times for all bytes from the array buf starting at index + * offset. Subclasses should overwrite this method to get a + * more efficient implementation. + * + * @param buf The byte array to write bytes from + * @param offset The index into the array to start writing bytes from + * @param len The number of bytes to write + * + * @exception IOException If an error occurs + */ + public void write(byte[] buf, int offset, int len) //throws IOException + { + // Don't do checking here, per Java Lang Spec. + for (int i=0; i < len; i++) + write(buf[offset + i]); + + } + +} // class FilterOutputStream + diff --git a/Robust/src/ClassLibrary/MGC/gnu/GregorianCalendar.java b/Robust/src/ClassLibrary/MGC/gnu/GregorianCalendar.java new file mode 100644 index 00000000..ebad0588 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/GregorianCalendar.java @@ -0,0 +1,1365 @@ +/* java.util.GregorianCalendar + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2007 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + + +/** + *

+ * This class represents the Gregorian calendar, that is used in most + * countries all over the world. It does also handle the Julian calendar + * for dates smaller than the date of the change to the Gregorian calendar. + * The Gregorian calendar differs from the Julian calendar by a different + * leap year rule (no leap year every 100 years, except if year is divisible + * by 400). + *

+ *

+ * This change date is different from country to country, and can be changed with + * setGregorianChange. The first countries to adopt the Gregorian + * calendar did so on the 15th of October, 1582. This date followed October + * the 4th, 1582 in the Julian calendar system. The non-existant days that were + * omitted when the change took place are interpreted as Gregorian dates. + *

+ *

+ * Prior to the changeover date, New Year's Day occurred on the 25th of March. + * However, this class always takes New Year's Day as being the 1st of January. + * Client code should manually adapt the year value, if required, for dates + * between January the 1st and March the 24th in years prior to the changeover. + *

+ *

+ * Any date infinitely forwards or backwards in time can be represented by + * this class. A proleptic calendar system is used, which allows + * future dates to be created via the existing rules. This allows meaningful + * and consistent dates to be produced for all years. However, dates are only + * historically accurate following March the 1st, 4AD when the Julian calendar + * system was adopted. Prior to this, leap year rules were applied erraticly. + *

+ *

+ * There are two eras available for the Gregorian calendar, namely BC and AD. + *

+ *

+ * Weeks are defined as a period of seven days, beginning on the first day + * of the week, as returned by getFirstDayOfWeek(), and ending + * on the day prior to this. + *

+ *

+ * The weeks of the year are numbered from 1 to a possible 53. The first week + * of the year is defined as the first week that contains at least the minimum + * number of days of the first week in the new year (retrieved via + * getMinimalDaysInFirstWeek()). All weeks after this are numbered + * from 2 onwards. + *

+ *

+ * For example, take the year 2004. It began on a Thursday. The first week + * of 2004 depends both on where a week begins and how long it must minimally + * last. Let's say that the week begins on a Monday and must have a minimum + * of 5 days. In this case, the first week begins on Monday, the 5th of January. + * The first 4 days (Thursday to Sunday) are not eligible, as they are too few + * to make up the minimum number of days of the first week which must be in + * the new year. If the minimum was lowered to 4 days, then the first week + * would instead begin on Monday, the 29th of December, 2003. This first week + * has 4 of its days in the new year, and is now eligible. + *

+ *

+ * The weeks of the month are numbered from 0 to a possible 6. The first week + * of the month (numbered 1) is a set of days, prior to the first day of the week, + * which number at least the minimum number of days in a week. Unlike the first + * week of the year, the first week of the month only uses days from that particular + * month. As a consequence, it may have a variable number of days (from the minimum + * number required up to a full week of 7) and it need not start on the first day of + * the week. It must, however, be following by the first day of the week, as this + * marks the beginning of week 2. Any days of the month which occur prior to the + * first week (because the first day of the week occurs before the minimum number + * of days is met) are seen as week 0. + *

+ *

+ * Again, we will take the example of the year 2004 to demonstrate this. September + * 2004 begins on a Wednesday. Taking our first day of the week as Monday, and the + * minimum length of the first week as 6, we find that week 1 runs from Monday, + * the 6th of September to Sunday the 12th. Prior to the 6th, there are only + * 5 days (Wednesday through to Sunday). This is too small a number to meet the + * minimum, so these are classed as being days in week 0. Week 2 begins on the + * 13th, and so on. This changes if we reduce the minimum to 5. In this case, + * week 1 is a truncated week from Wednesday the 1st to Sunday the 5th, and week + * 0 doesn't exist. The first seven day week is week 2, starting on the 6th. + *

+ *

+ * On using the clear() method, the Gregorian calendar returns + * to its default value of the 1st of January, 1970 AD 00:00:00 (the epoch). + * The day of the week is set to the correct day for that particular time. + * The day is also the first of the month, and the date is in week 0. + *

+ * + * @see Calendar + * @see TimeZone + * @see Calendar#getFirstDayOfWeek() + * @see Calendar#getMinimalDaysInFirstWeek() + */ +public class GregorianCalendar extends Calendar +{ + /** + * Constant representing the era BC (Before Christ). + */ + public static final int BC = 0; + + /** + * Constant representing the era AD (Anno Domini). + */ + public static final int AD = 1; + + /** + * The point at which the Gregorian calendar rules were used. + * This may be changed by using setGregorianChange; + * The default is midnight (UTC) on October 5, 1582 (Julian), + * or October 15, 1582 (Gregorian). + * + * @serial the changeover point from the Julian calendar + * system to the Gregorian. + */ + private long gregorianCutover = (new Date((24 * 60 * 60 * 1000L) * (((1582 * (365 * 4 + + 1)) / 4 + + (java.util.Calendar.OCTOBER * (31 + + 30 + 31 + 30 + 31) - 9) / 5 + 5) + - ((1970 * (365 * 4 + 1)) / 4 + 1 + - 13)))).getTime(); + + /** + * For compatability with Sun's JDK. + */ + static final long serialVersionUID = -8125100834729963327L; + + /** + * Days in the epoch. Relative Jan 1, year '0' which is not a leap year. + * (although there is no year zero, this does not matter.) + * This is consistent with the formula: + * = (year-1)*365L + ((year-1) >> 2) + * + * Plus the gregorian correction: + * Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.); + * For a correct julian date, the correction is -2 instead. + * + * The gregorian cutover in 1582 was 10 days, so by calculating the + * correction from year zero, we have 15 non-leap days (even centuries) + * minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects + * this to the correct number 10. + */ + private static final int EPOCH_DAYS = 719162; + + /** + * Constructs a new GregorianCalender representing the current + * time, using the default time zone and the default locale. + */ + public GregorianCalendar() + { + this(/*TimeZone.getDefault(), */Locale.getDefault()); + } + + /** + * Constructs a new GregorianCalender representing the current + * time, using the specified time zone and the default locale. + * + * @param zone a time zone. + */ + /*public GregorianCalendar(TimeZone zone) + { + this(zone, Locale.getDefault()); + }*/ + + /** + * Constructs a new GregorianCalender representing the current + * time, using the default time zone and the specified locale. + * + * @param locale a locale. + */ + public GregorianCalendar(Locale locale) + { + this(/*TimeZone.getDefault(), */locale); + } + + /** + * Constructs a new GregorianCalender representing the current + * time with the given time zone and the given locale. + * + * @param zone a time zone. + * @param locale a locale. + */ + /*public GregorianCalendar(TimeZone zone, Locale locale) + { + this(zone, locale, false); + setTimeInMillis(System.currentTimeMillis()); + }*/ + + /** + * Common constructor that all constructors should call. + * @param zone a time zone. + * @param locale a locale. + * @param unused unused parameter to make the signature differ from + * the public constructor (TimeZone, Locale). + */ + private GregorianCalendar(/*TimeZone zone, */Locale locale, boolean unused) + { + super(/*zone, */locale); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + */ + public GregorianCalendar(int year, int month, int day) + { + this(/*TimeZone.getDefault(), */Locale.getDefault(), false); + set(year, month, day); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + * @param hour corresponds to the HOUR_OF_DAY time field. + * @param minute corresponds to the MINUTE time field. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute) + { + this(/*TimeZone.getDefault(), */Locale.getDefault(), false); + set(year, month, day, hour, minute); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + * @param hour corresponds to the HOUR_OF_DAY time field. + * @param minute corresponds to the MINUTE time field. + * @param second corresponds to the SECOND time field. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute, + int second) + { + this(/*TimeZone.getDefault(), */Locale.getDefault(), false); + set(year, month, day, hour, minute, second); + } + + /** + * Sets the date of the switch from Julian dates to Gregorian dates. + * You can use new Date(Long.MAX_VALUE) to use a pure + * Julian calendar, or Long.MIN_VALUE for a pure Gregorian + * calendar. + * + * @param date the date of the change. + */ + public void setGregorianChange(Date date) + { + gregorianCutover = date.getTime(); + } + + /** + * Gets the date of the switch from Julian dates to Gregorian dates. + * + * @return the date of the change. + */ + public final Date getGregorianChange() + { + return new Date(gregorianCutover); + } + + /** + *

+ * Determines if the given year is a leap year. The result is + * undefined if the Gregorian change took place in 1800, so that + * the end of February is skipped, and that year is specified. + * (well...). + *

+ *

+ * To specify a year in the BC era, use a negative value calculated + * as 1 - y, where y is the required year in BC. So, 1 BC is 0, + * 2 BC is -1, 3 BC is -2, etc. + *

+ * + * @param year a year (use a negative value for BC). + * @return true, if the given year is a leap year, false otherwise. + */ + public boolean isLeapYear(int year) + { + // Only years divisible by 4 can be leap years + if ((year & 3) != 0) + return false; + + // Is the leap-day a Julian date? Then it's a leap year + if (! isGregorian(year, 31 + 29 - 1)) + return true; + + // Apply gregorian rules otherwise + return ((year % 100) != 0 || (year % 400) == 0); + } + + /** + * Retrieves the day of the week corresponding to the specified + * day of the specified year. + * + * @param year the year in which the dayOfYear occurs. + * @param dayOfYear the day of the year (an integer between 0 and + * and 366) + */ + private int getWeekDay(int year, int dayOfYear) + { + boolean greg = isGregorian(year, dayOfYear); + int day = (int) getLinearDay(year, dayOfYear, greg); + + // The epoch was a thursday. + int weekday = (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + return weekday; + } + + /** + * Returns the day of the week for the first day of a given month (0..11) + */ + private int getFirstDayOfMonth(int year, int month) + { + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + if (month > 11) + { + year += (month / 12); + month = month % 12; + } + + if (month < 0) + { + year += (int) month / 12; + month = month % 12; + if (month < 0) + { + month += 12; + year--; + } + } + + int dayOfYear = dayCount[month] + 1; + if (month > 1) + if (isLeapYear(year)) + dayOfYear++; + + boolean greg = isGregorian(year, dayOfYear); + int day = (int) getLinearDay(year, dayOfYear, greg); + + // The epoch was a thursday. + int weekday = (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + return weekday; + } + + /** + * Takes a year, and a (zero based) day of year and determines + * if it is gregorian or not. + */ + private boolean isGregorian(int year, int dayOfYear) + { + int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear + - EPOCH_DAYS; // gregorian days from 1 to epoch. + int gregFactor = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover); + } + + /** + * Check set fields for validity, without leniency. + * + * @throws IllegalArgumentException if a field is invalid + */ + private void nonLeniencyCheck() throws IllegalArgumentException + { + int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int year = fields[YEAR]; + int month = fields[MONTH]; + int leap = isLeapYear(year) ? 1 : 0; + + if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC) + throw new IllegalArgumentException("Illegal ERA."); + if (isSet[YEAR] && fields[YEAR] < 1) + throw new IllegalArgumentException("Illegal YEAR."); + if (isSet[MONTH] && (month < 0 || month > 11)) + throw new IllegalArgumentException("Illegal MONTH."); + if (isSet[WEEK_OF_YEAR]) + { + int daysInYear = 365 + leap; + daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week + int last = getFirstDayOfMonth(year, 11) + 4; + if (last > 7) + last -= 7; + daysInYear += 7 - last; + int weeks = daysInYear / 7; + if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks) + throw new IllegalArgumentException("Illegal WEEK_OF_YEAR."); + } + + if (isSet[WEEK_OF_MONTH]) + { + int weeks = (month == 1 && leap == 0) ? 5 : 6; + if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks) + throw new IllegalArgumentException("Illegal WEEK_OF_MONTH."); + } + + if (isSet[DAY_OF_MONTH]) + if (fields[DAY_OF_MONTH] < 1 + || fields[DAY_OF_MONTH] > month_days[month] + + ((month == 1) ? leap : 0)) + throw new IllegalArgumentException("Illegal DAY_OF_MONTH."); + + if (isSet[DAY_OF_YEAR] + && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap)) + throw new IllegalArgumentException("Illegal DAY_OF_YEAR."); + + if (isSet[DAY_OF_WEEK] + && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) + throw new IllegalArgumentException("Illegal DAY_OF_WEEK."); + + if (isSet[DAY_OF_WEEK_IN_MONTH]) + { + int weeks = (month == 1 && leap == 0) ? 4 : 5; + if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks + || fields[DAY_OF_WEEK_IN_MONTH] > weeks) + throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH."); + } + + if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) + throw new IllegalArgumentException("Illegal AM_PM."); + if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) + throw new IllegalArgumentException("Illegal HOUR."); + if (isSet[HOUR_OF_DAY] + && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23)) + throw new IllegalArgumentException("Illegal HOUR_OF_DAY."); + if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) + throw new IllegalArgumentException("Illegal MINUTE."); + if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) + throw new IllegalArgumentException("Illegal SECOND."); + if (isSet[MILLISECOND] + && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) + throw new IllegalArgumentException("Illegal MILLISECOND."); + if (isSet[ZONE_OFFSET] + && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L + || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L)) + throw new IllegalArgumentException("Illegal ZONE_OFFSET."); + if (isSet[DST_OFFSET] + && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L + || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L)) + throw new IllegalArgumentException("Illegal DST_OFFSET."); + } + + /** + * Converts the time field values (fields) to + * milliseconds since the epoch UTC (time). + * + * @throws IllegalArgumentException if any calendar fields + * are invalid. + */ + protected synchronized void computeTime() + { + int millisInDay = 0; + int era = fields[ERA]; + int year = fields[YEAR]; + int month = fields[MONTH]; + int day = fields[DAY_OF_MONTH]; + + int minute = fields[MINUTE]; + int second = fields[SECOND]; + int millis = fields[MILLISECOND]; + int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int hour = 0; + + if (! isLenient()) + nonLeniencyCheck(); + + if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR])) + { + // 5: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + if (isSet[WEEK_OF_YEAR]) + { + int first = getFirstDayOfMonth(year, 0); + int offs = 1; + int daysInFirstWeek = getFirstDayOfWeek() - first; + if (daysInFirstWeek <= 0) + daysInFirstWeek += 7; + + if (daysInFirstWeek < getMinimalDaysInFirstWeek()) + offs += daysInFirstWeek; + else + offs -= 7 - daysInFirstWeek; + month = 0; + day = offs + 7 * (fields[WEEK_OF_YEAR] - 1); + offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek(); + + if (offs < 0) + offs += 7; + day += offs; + } + else + { + // 4: YEAR + DAY_OF_YEAR + month = 0; + day = fields[DAY_OF_YEAR]; + } + } + else + { + if (isSet[DAY_OF_WEEK]) + { + int first = getFirstDayOfMonth(year, month); + + // 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + if (isSet[DAY_OF_WEEK_IN_MONTH]) + { + if (fields[DAY_OF_WEEK_IN_MONTH] < 0) + { + month++; + first = getFirstDayOfMonth(year, month); + day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]); + } + else + day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1); + + int offs = fields[DAY_OF_WEEK] - first; + if (offs < 0) + offs += 7; + day += offs; + } + else + { // 2: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + int offs = 1; + int daysInFirstWeek = getFirstDayOfWeek() - first; + if (daysInFirstWeek <= 0) + daysInFirstWeek += 7; + + if (daysInFirstWeek < getMinimalDaysInFirstWeek()) + offs += daysInFirstWeek; + else + offs -= 7 - daysInFirstWeek; + + day = offs + 7 * (fields[WEEK_OF_MONTH] - 1); + offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek(); + if (offs < 0) + offs += 7; + day += offs; + } + } + + // 1: YEAR + MONTH + DAY_OF_MONTH + } + if (era == BC && year > 0) + year = 1 - year; + + // rest of code assumes day/month/year set + // should negative BC years be AD? + // get the hour (but no check for validity) + if (isSet[HOUR]) + { + hour = fields[HOUR]; + if (fields[AM_PM] == PM) + hour += 12; + } + else + hour = fields[HOUR_OF_DAY]; + + // Read the era,year,month,day fields and convert as appropriate. + // Calculate number of milliseconds into the day + // This takes care of both h, m, s, ms over/underflows. + long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis; + day += allMillis / (24 * 60 * 60 * 1000L); + millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); + + if (month < 0) + { + year += (int) month / 12; + month = month % 12; + if (month < 0) + { + month += 12; + year--; + } + } + if (month > 11) + { + year += (month / 12); + month = month % 12; + } + + month_days[1] = isLeapYear(year) ? 29 : 28; + + while (day <= 0) + { + if (month == 0) + { + year--; + month_days[1] = isLeapYear(year) ? 29 : 28; + } + month = (month + 11) % 12; + day += month_days[month]; + } + while (day > month_days[month]) + { + day -= (month_days[month]); + month = (month + 1) % 12; + if (month == 0) + { + year++; + month_days[1] = isLeapYear(year) ? 29 : 28; + } + } + + // ok, by here we have valid day,month,year,era and millisinday + int dayOfYear = dayCount[month] + day - 1; // (day starts on 1) + if (isLeapYear(year) && month > 1) + dayOfYear++; + + int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear + - EPOCH_DAYS; // gregorian days from 1 to epoch. + int gregFactor = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover) + relativeDay += gregFactor; + else + relativeDay -= 2; + + time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay; + + // the epoch was a Thursday. + int weekday = (int) (relativeDay + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + fields[DAY_OF_WEEK] = weekday; + + // Time zone corrections. + TimeZone zone = getTimeZone(); + int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET] + : zone.getRawOffset(); + + int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET] + : (zone.getOffset((year < 0) ? BC : AD, + (year < 0) ? 1 - year + : year, + month, day, weekday, + millisInDay) + - zone.getRawOffset()); + + time -= rawOffset + dstOffset; + + isTimeSet = true; + } + + /** + * Get the linear day in days since the epoch, using the + * Julian or Gregorian calendar as specified. If you specify a + * nonpositive year it is interpreted as BC as following: 0 is 1 + * BC, -1 is 2 BC and so on. + * + * @param year the year of the date. + * @param dayOfYear the day of year of the date; 1 based. + * @param gregorian true, if we should use the Gregorian rules. + * @return the days since the epoch, may be negative. + */ + private long getLinearDay(int year, int dayOfYear, boolean gregorian) + { + // The 13 is the number of days, that were omitted in the Gregorian + // Calender until the epoch. + // We shift right by 2 instead of dividing by 4, to get correct + // results for negative years (and this is even more efficient). + long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1) + - EPOCH_DAYS; // gregorian days from 1 to epoch. + + if (gregorian) + { + // subtract the days that are missing in gregorian calendar + // with respect to julian calendar. + // + // Okay, here we rely on the fact that the gregorian + // calendar was introduced in the AD era. This doesn't work + // with negative years. + // + // The additional leap year factor accounts for the fact that + // a leap day is not seen on Jan 1 of the leap year. + int gregOffset = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + return julianDay + gregOffset; + } + else + julianDay -= 2; + return julianDay; + } + + /** + * Converts the given linear day into era, year, month, + * day_of_year, day_of_month, day_of_week, and writes the result + * into the fields array. + * + * @param day the linear day. + * @param gregorian true, if we should use Gregorian rules. + */ + private void calculateDay(int[] fields, long day, boolean gregorian) + { + // the epoch was a Thursday. + int weekday = (int) (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + fields[DAY_OF_WEEK] = weekday; + + // get a first approximation of the year. This may be one + // year too big. + int year = 1970 + + (int) (gregorian + ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L + + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L)); + if (day >= 0) + year++; + + long firstDayOfYear = getLinearDay(year, 1, gregorian); + + // Now look in which year day really lies. + if (day < firstDayOfYear) + { + year--; + firstDayOfYear = getLinearDay(year, 1, gregorian); + } + + day -= firstDayOfYear - 1; // day of year, one based. + + fields[DAY_OF_YEAR] = (int) day; + if (year <= 0) + { + fields[ERA] = BC; + fields[YEAR] = 1 - year; + } + else + { + fields[ERA] = AD; + fields[YEAR] = year; + } + + int leapday = isLeapYear(year) ? 1 : 0; + if (day <= 31 + 28 + leapday) + { + fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY + fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH]; + } + else + { + // A few more magic formulas + int scaledDay = ((int) day - leapday) * 5 + 8; + fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31); + fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1; + } + } + + /** + * Converts the milliseconds since the epoch UTC + * (time) to time fields + * (fields). + */ + protected synchronized void computeFields() + { + boolean gregorian = (time >= gregorianCutover); + + TimeZone zone = getTimeZone(); + fields[ZONE_OFFSET] = zone.getRawOffset(); + long localTime = time + fields[ZONE_OFFSET]; + + long day = localTime / (24 * 60 * 60 * 1000L); + int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); + + if (millisInDay < 0) + { + millisInDay += (24 * 60 * 60 * 1000); + day--; + } + + calculateDay(fields, day, gregorian); + fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR], + fields[MONTH], fields[DAY_OF_MONTH], + fields[DAY_OF_WEEK], millisInDay) + - fields[ZONE_OFFSET]; + + millisInDay += fields[DST_OFFSET]; + if (millisInDay >= 24 * 60 * 60 * 1000) + { + millisInDay -= 24 * 60 * 60 * 1000; + calculateDay(fields, ++day, gregorian); + } + + fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7; + + // which day of the week are we (0..6), relative to getFirstDayOfWeek + int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7; + + // which day of the week is the first of this month? + // nb 35 is the smallest multiple of 7 that ensures that + // the left hand side of the modulo operator is positive. + int relativeWeekdayOfFirst = (relativeWeekday - fields[DAY_OF_MONTH] + + 1 + 35) % 7; + + // which week of the month is the first of this month in? + int minDays = getMinimalDaysInFirstWeek(); + int weekOfFirst = ((7 - relativeWeekdayOfFirst) >= minDays) ? 1 : 0; + + // which week of the month is this day in? + fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] + + relativeWeekdayOfFirst - 1) / 7 + weekOfFirst; + + int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7; + + // Do the Correction: getMinimalDaysInFirstWeek() is always in the + // first week. + int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays) + - getFirstDayOfWeek()) % 7; + if (minDays - firstWeekday < 1) + weekOfYear++; + fields[WEEK_OF_YEAR] = weekOfYear; + + int hourOfDay = millisInDay / (60 * 60 * 1000); + fields[AM_PM] = (hourOfDay < 12) ? AM : PM; + int hour = hourOfDay % 12; + fields[HOUR] = hour; + fields[HOUR_OF_DAY] = hourOfDay; + millisInDay %= (60 * 60 * 1000); + fields[MINUTE] = millisInDay / (60 * 1000); + millisInDay %= (60 * 1000); + fields[SECOND] = millisInDay / (1000); + fields[MILLISECOND] = millisInDay % 1000; + + areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] = isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] = isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] = isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] = isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true; + } + + /** + * Return a hash code for this object, following the general contract + * specified by {@link Object#hashCode()}. + * @return the hash code + */ + public int hashCode() + { + int val = (int) ((gregorianCutover >>> 32) ^ (gregorianCutover & 0xffffffff)); + return super.hashCode() ^ val; + } + + /** + * Compares the given calendar with this. An object, o, is + * equivalent to this if it is also a GregorianCalendar + * with the same time since the epoch under the same conditions + * (same change date and same time zone). + * + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessarily have the same fields). + * @throws IllegalArgumentException if one of the fields + * ZONE_OFFSET or DST_OFFSET is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public boolean equals(Object o) + { + if (! (o instanceof GregorianCalendar)) + return false; + + GregorianCalendar cal = (GregorianCalendar) o; + return (cal.gregorianCutover == gregorianCutover + && super.equals(o)); + } + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field one of the time field constants. + * @param amount the amount of time to add. + * @exception IllegalArgumentException if field is + * ZONE_OFFSET, DST_OFFSET, or invalid; or + * if amount contains an out-of-range value and the calendar + * is not in lenient mode. + */ + public void add(int field, int amount) + { + switch (field) + { + case YEAR: + complete(); + fields[YEAR] += amount; + isTimeSet = false; + break; + case MONTH: + complete(); + int months = fields[MONTH] + amount; + fields[YEAR] += months / 12; + fields[MONTH] = months % 12; + if (fields[MONTH] < 0) + { + fields[MONTH] += 12; + fields[YEAR]--; + } + int maxDay = getActualMaximum(DAY_OF_MONTH); + if (fields[DAY_OF_MONTH] > maxDay) + fields[DAY_OF_MONTH] = maxDay; + set(YEAR, fields[YEAR]); + set(MONTH, fields[MONTH]); + break; + case DAY_OF_MONTH: + case DAY_OF_YEAR: + case DAY_OF_WEEK: + if (! isTimeSet) + computeTime(); + time += amount * (24 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case WEEK_OF_YEAR: + case WEEK_OF_MONTH: + case DAY_OF_WEEK_IN_MONTH: + if (! isTimeSet) + computeTime(); + time += amount * (7 * 24 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case AM_PM: + if (! isTimeSet) + computeTime(); + time += amount * (12 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case HOUR: + case HOUR_OF_DAY: + if (! isTimeSet) + computeTime(); + time += amount * (60 * 60 * 1000L); + areFieldsSet = false; + break; + case MINUTE: + if (! isTimeSet) + computeTime(); + time += amount * (60 * 1000L); + areFieldsSet = false; + break; + case SECOND: + if (! isTimeSet) + computeTime(); + time += amount * (1000L); + areFieldsSet = false; + break; + case MILLISECOND: + if (! isTimeSet) + computeTime(); + time += amount; + areFieldsSet = false; + break; + case ZONE_OFFSET: + case DST_OFFSET:default: + throw new IllegalArgumentException("Invalid or unknown field"); + } + } + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value. + * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * This requires lenient settings. + * + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws IllegalArgumentException if one of the fields + * ZONE_OFFSET or DST_OFFSET is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public void roll(int field, boolean up) + { + roll(field, up ? 1 : -1); + } + + /** + * Checks that the fields are still within their legal bounds, + * following use of the roll() method. + * + * @param field the field to check. + * @param delta multipler for alterations to the time. + * @see #roll(int, boolean) + * @see #roll(int, int) + */ + private void cleanUpAfterRoll(int field, int delta) + { + switch (field) + { + case ERA: + case YEAR: + case MONTH: + // check that day of month is still in correct range + if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH)) + fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH); + isTimeSet = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (24 * 60 * 60 * 1000L); + break; + case WEEK_OF_MONTH: + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case DAY_OF_WEEK_IN_MONTH: + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case DAY_OF_YEAR: + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (24 * 60 * 60 * 1000L); + break; + case WEEK_OF_YEAR: + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case AM_PM: + isSet[HOUR_OF_DAY] = false; + time += delta * (12 * 60 * 60 * 1000L); + break; + case HOUR: + isSet[HOUR_OF_DAY] = false; + time += delta * (60 * 60 * 1000L); + break; + case HOUR_OF_DAY: + isSet[HOUR] = false; + isSet[AM_PM] = false; + time += delta * (60 * 60 * 1000L); + break; + case MINUTE: + time += delta * (60 * 1000L); + break; + case SECOND: + time += delta * (1000L); + break; + case MILLISECOND: + time += delta; + break; + } + } + + /** + * Rolls the specified time field by the given amount. This means + * add amount to the specified field, but don't change the other + * fields. If the maximum for this field is reached, start over + * with the minimum value and vice versa for negative amounts. + * + * Note: There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically corrected to June, 30. + * + * @param field the time field. One of the time field constants. + * @param amount the amount by which we should roll. + * @throws IllegalArgumentException if one of the fields + * ZONE_OFFSET or DST_OFFSET is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public void roll(int field, int amount) + { + switch (field) + { + case DAY_OF_WEEK: + // day of week is special: it rolls automatically + add(field, amount); + return; + case ZONE_OFFSET: + case DST_OFFSET: + throw new IllegalArgumentException("Can't roll time zone"); + } + complete(); + int min = getActualMinimum(field); + int range = getActualMaximum(field) - min + 1; + int oldval = fields[field]; + int newval = (oldval - min + range + amount) % range + min; + if (newval < min) + newval += range; + fields[field] = newval; + cleanUpAfterRoll(field, newval - oldval); + } + + /** + * The minimum values for the calendar fields. + */ + private static final int[] minimums = + { + BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM, + 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000), + 0 + }; + + /** + * The maximum values for the calendar fields. + */ + private static final int[] maximums = + { + AD, 5000000, 11, 53, 6, 31, 366, + SATURDAY, 5, PM, 12, 23, 59, 59, 999, + +(12 * 60 * 60 * 1000), + (12 * 60 * 60 * 1000) + }; + + /** + * Gets the smallest value that is allowed for the specified field. + * + * @param field one of the time field constants. + * @return the smallest value for the specified field. + */ + public int getMinimum(int field) + { + return minimums[field]; + } + + /** + * Gets the biggest value that is allowed for the specified field. + * + * @param field one of the time field constants. + * @return the biggest value. + */ + public int getMaximum(int field) + { + return maximums[field]; + } + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * This is the largest value returned by the getActualMinimum(int) + * method. + * + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + * @see #getActualMinimum(int) + */ + public int getGreatestMinimum(int field) + { + if (field == WEEK_OF_YEAR) + return 1; + return minimums[field]; + } + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. This is the smallest value returned + * by the getActualMaximum(int). For example, + * this is 28 for DAY_OF_MONTH (as all months have at least + * 28 days). + * + * @param field the time field. One of the time field constants. + * @return the least maximum value. + * @see #getActualMaximum(int) + * @since 1.2 + */ + public int getLeastMaximum(int field) + { + switch (field) + { + case WEEK_OF_YEAR: + return 52; + case DAY_OF_MONTH: + return 28; + case DAY_OF_YEAR: + return 365; + case DAY_OF_WEEK_IN_MONTH: + case WEEK_OF_MONTH: + return 4; + default: + return maximums[field]; + } + } + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. Note that + * this calls complete() if not enough fields are set. This + * can have ugly side effects. The value given depends on the current + * time used by this instance. + * + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @since 1.2 + */ + public int getActualMinimum(int field) + { + if (field == WEEK_OF_YEAR) + { + int min = getMinimalDaysInFirstWeek(); + if (min == 0) + return 1; + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + int weekday = getWeekDay(year, min); + if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1) + return 1; + return 0; + } + return minimums[field]; + } + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. Note that + * this calls complete() if not enough fields are set. This + * can have ugly side effects. The value given depends on the current time + * used by this instance; thus, leap years have a maximum day of month value of + * 29, rather than 28. + * + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + */ + public int getActualMaximum(int field) + { + switch (field) + { + case WEEK_OF_YEAR: + { + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + + // This is wrong for the year that contains the gregorian change. + // I.e it gives the weeks in the julian year or in the gregorian + // year in that case. + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + int lastDay = isLeapYear(year) ? 366 : 365; + int weekday = getWeekDay(year, lastDay); + int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7; + + int minimalDays = getMinimalDaysInFirstWeek(); + int firstWeekday = getWeekDay(year, minimalDays); + /* + * Is there a set of days at the beginning of the year, before the + * first day of the week, equal to or greater than the minimum number + * of days required in the first week? + */ + if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1) + return week + 1; /* Add week 1: firstWeekday through to firstDayOfWeek */ + } + case DAY_OF_MONTH: + { + if (! areFieldsSet || ! isSet[MONTH]) + complete(); + int month = fields[MONTH]; + + // If you change this, you should also change + // SimpleTimeZone.getDaysInMonth(); + if (month == FEBRUARY) + { + if (! isSet[YEAR] || ! isSet[ERA]) + complete(); + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + return isLeapYear(year) ? 29 : 28; + } + else if (month < AUGUST) + return 31 - (month & 1); + else + return 30 + (month & 1); + } + case DAY_OF_YEAR: + { + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + return isLeapYear(year) ? 366 : 365; + } + case DAY_OF_WEEK_IN_MONTH: + { + // This is wrong for the month that contains the gregorian change. + int daysInMonth = getActualMaximum(DAY_OF_MONTH); + + // That's black magic, I know + return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7; + } + case WEEK_OF_MONTH: + { + int daysInMonth = getActualMaximum(DAY_OF_MONTH); + int weekday = (daysInMonth - fields[DAY_OF_MONTH] + + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY; + return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7; + } + default: + return maximums[field]; + } + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/Locale.java b/Robust/src/ClassLibrary/MGC/gnu/Locale.java new file mode 100644 index 00000000..2d4105a8 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Locale.java @@ -0,0 +1,1029 @@ +/* Locale.java -- i18n locales + Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/*import gnu.classpath.SystemProperties; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.locale.LocaleHelper; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import java.util.spi.LocaleNameProvider;*/ + +/** + * Locales represent a specific country and culture. Classes which can be + * passed a Locale object tailor their information for a given locale. For + * instance, currency number formatting is handled differently for the USA + * and France. + * + *

Locales are made up of a language code, a country code, and an optional + * set of variant strings. Language codes are represented by + * + * ISO 639:1988 w/ additions from ISO 639/RA Newsletter No. 1/1989 + * and a decision of the Advisory Committee of ISO/TC39 on August 8, 1997. + * + *

Country codes are represented by + * + * ISO 3166. Variant strings are vendor and browser specific. Standard + * variant strings include "POSIX" for POSIX, "WIN" for MS-Windows, and + * "MAC" for Macintosh. When there is more than one variant string, they must + * be separated by an underscore (U+005F). + * + *

The default locale is determined by the values of the system properties + * user.language, user.country (or user.region), and user.variant, defaulting + * to "en_US". Note that the locale does NOT contain the conversion and + * formatting capabilities (for that, use ResourceBundle and java.text). + * Rather, it is an immutable tag object for identifying a given locale, which + * is referenced by these other classes when they must make locale-dependent + * decisions. + * + * @see ResourceBundle + * @see java.text.Format + * @see java.text.NumberFormat + * @see java.text.Collator + * @author Jochen Hoenicke + * @author Paul Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.1 + * @status updated to 1.4 + */ +public final class Locale //implements Serializable, Cloneable +{ + /** Locale which represents the English language. */ + public static final Locale ENGLISH = getLocale("en"); + + /** Locale which represents the French language. */ + public static final Locale FRENCH = getLocale("fr"); + + /** Locale which represents the German language. */ + public static final Locale GERMAN = getLocale("de"); + + /** Locale which represents the Italian language. */ + public static final Locale ITALIAN = getLocale("it"); + + /** Locale which represents the Japanese language. */ + public static final Locale JAPANESE = getLocale("ja"); + + /** Locale which represents the Korean language. */ + public static final Locale KOREAN = getLocale("ko"); + + /** Locale which represents the Chinese language. */ + public static final Locale CHINESE = getLocale("zh"); + + /** Locale which represents the Chinese language as used in China. */ + public static final Locale SIMPLIFIED_CHINESE = getLocale("zh", "CN"); + + /** + * Locale which represents the Chinese language as used in Taiwan. + * Same as TAIWAN Locale. + */ + public static final Locale TRADITIONAL_CHINESE = getLocale("zh", "TW"); + + /** Locale which represents France. */ + public static final Locale FRANCE = getLocale("fr", "FR"); + + /** Locale which represents Germany. */ + public static final Locale GERMANY = getLocale("de", "DE"); + + /** Locale which represents Italy. */ + public static final Locale ITALY = getLocale("it", "IT"); + + /** Locale which represents Japan. */ + public static final Locale JAPAN = getLocale("ja", "JP"); + + /** Locale which represents Korea. */ + public static final Locale KOREA = getLocale("ko", "KR"); + + /** + * Locale which represents China. + * Same as SIMPLIFIED_CHINESE Locale. + */ + public static final Locale CHINA = SIMPLIFIED_CHINESE; + + /** + * Locale which represents the People's Republic of China. + * Same as CHINA Locale. + */ + public static final Locale PRC = CHINA; + + /** + * Locale which represents Taiwan. + * Same as TRADITIONAL_CHINESE Locale. + */ + public static final Locale TAIWAN = TRADITIONAL_CHINESE; + + /** Locale which represents the United Kingdom. */ + public static final Locale UK = getLocale("en", "GB"); + + /** Locale which represents the United States. */ + public static final Locale US = getLocale("en", "US"); + + /** Locale which represents the English speaking portion of Canada. */ + public static final Locale CANADA = getLocale("en", "CA"); + + /** Locale which represents the French speaking portion of Canada. */ + public static final Locale CANADA_FRENCH = getLocale("fr", "CA"); + + /** The root locale, used as the base case in lookups by + * locale-sensitive operations. + */ + public static final Locale ROOT = new Locale("","",""); + + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 9149081749638150636L; + + /** + * The language code, as returned by getLanguage(). + * + * @serial the languange, possibly "" + */ + private final String language; + + /** + * The country code, as returned by getCountry(). + * + * @serial the country, possibly "" + */ + private final String country; + + /** + * The variant code, as returned by getVariant(). + * + * @serial the variant, possibly "" + */ + private final String variant; + + /** + * This is the cached hashcode. When writing to stream, we write -1. + * + * @serial should be -1 in serial streams + */ + private int hashcode; + + /** + * Array storing all available locales. + */ + private static transient Locale[] availableLocales; + + /** + * Locale cache. Only created locale objects are stored. + * Contains all supported locales when getAvailableLocales() + * got called. + */ + private static transient HashMap localeMap; + + /** + * The default locale. Except for during bootstrapping, this should never be + * null. Note the logic in the main constructor, to detect when + * bootstrapping has completed. + */ + private static Locale defaultLocale; + + static { + String language = "en"; //SystemProperties.getProperty("user.language", "en"); + String country = "US"; //SystemProperties.getProperty("user.country", "US"); + String region = null; //SystemProperties.getProperty("user.region", null); + String variant = ""; //SystemProperties.getProperty("user.variant", ""); + + defaultLocale = getLocale(language, + (region != null) ? region : country, + variant); + } + + /** + * Array storing all the available two-letter ISO639 languages. + */ + private static transient String[] languageCache; + + /** + * Array storing all the available two-letter ISO3166 country codes. + */ + private static transient String[] countryCache; + + /** + * Retrieves the locale with the specified language from the cache. + * + * @param language the language of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language) + { + return getLocale(language, "", ""); + } + + /** + * Retrieves the locale with the specified language and country + * from the cache. + * + * @param language the language of the locale to retrieve. + * @param country the country of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language, String country) + { + return getLocale(language, country, ""); + } + + /** + * Retrieves the locale with the specified language, country + * and variant from the cache. + * + * @param language the language of the locale to retrieve. + * @param country the country of the locale to retrieve. + * @param variant the variant of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language, String country, String variant) + { + if (localeMap == null) + localeMap = new HashMap(256); + + String name = language + "_" + country + "_" + variant; + Locale locale = (Locale) localeMap.get(name); + + if (locale == null) + { + locale = new Locale(language, country, variant); + localeMap.put(name, locale); + } + + return locale; + } + + /** + * Convert new iso639 codes to the old ones. + * + * @param language the language to check + * @return the appropriate code + */ + private String convertLanguage(String language) + { + if (language.equals("")) + return language; + language = language.toLowerCase(); + int index = "he,id,yi".indexOf(language); + if (index != -1) + return "iw,in,ji".substring(index, index + 2); + return language; + } + + /** + * Creates a new locale for the given language and country. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @param country uppercase two-letter ISO-3166 A2 contry code + * @param variant vendor and browser specific + * @throws NullPointerException if any argument is null + */ + public Locale(String language, String country, String variant) + { + // During bootstrap, we already know the strings being passed in are + // the correct capitalization, and not null. We can't call + // String.toUpperCase during this time, since that depends on the + // default locale. + if (defaultLocale != null) + { + language = convertLanguage(language); + country = country.toUpperCase(); + } + this.language = language.intern(); + this.country = country.intern(); + this.variant = variant.intern(); + hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + } + + /** + * Creates a new locale for the given language and country. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @param country uppercase two-letter ISO-3166 A2 country code + * @throws NullPointerException if either argument is null + */ + public Locale(String language, String country) + { + this(language, country, ""); + } + + /** + * Creates a new locale for a language. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @throws NullPointerException if either argument is null + * @since 1.4 + */ + public Locale(String language) + { + this(language, "", ""); + } + + /** + * Returns the default Locale. The default locale is generally once set + * on start up and then never changed. Normally you should use this locale + * for everywhere you need a locale. The initial setting matches the + * default locale, the user has chosen. + * + * @return the default locale for this virtual machine + */ + public static Locale getDefault() + { + return defaultLocale; + } + + /** + * Changes the default locale. Normally only called on program start up. + * Note that this doesn't change the locale for other programs. This has + * a security check, + * PropertyPermission("user.language", "write"), because of + * its potential impact to running code. + * + * @param newLocale the new default locale + * @throws NullPointerException if newLocale is null + * @throws SecurityException if permission is denied + */ + public static void setDefault(Locale newLocale) + { + if (newLocale == null) + throw new NullPointerException(); + /*SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission("user.language", "write"));*/ + defaultLocale = newLocale; + } + + /** + * Returns the list of available locales. + * + * @return the installed locales + */ + public static synchronized Locale[] getAvailableLocales() + { + if (availableLocales == null) + { + int len = LocaleHelper.getLocaleCount(); + availableLocales = new Locale[len]; + + for (int i = 0; i < len; i++) + { + String language; + String country = ""; + String variant = ""; + String name = LocaleHelper.getLocaleName(i); + + language = name.substring(0, 2); + + if (name.length() > 2) + country = name.substring(3); + + int index = country.indexOf("_"); + if (index > 0) + { + variant = country.substring(index + 1); + country = country.substring(0, index - 1); + } + + availableLocales[i] = getLocale(language, country, variant); + } + } + + return (Locale[]) availableLocales.clone(); + } + + /** + * Returns a list of all 2-letter uppercase country codes as defined + * in ISO 3166. + * + * @return a list of acceptable country codes + */ + public static String[] getISOCountries() + { + if (countryCache == null) + { + countryCache = getISOStrings("territories"); + } + + return (String[]) countryCache.clone(); + } + + /** + * Returns a list of all 2-letter lowercase language codes as defined + * in ISO 639 (both old and new variant). + * + * @return a list of acceptable language codes + */ + public static String[] getISOLanguages() + { + if (languageCache == null) + { + languageCache = getISOStrings("languages"); + } + return (String[]) languageCache.clone(); + } + + /** + * Returns the set of keys from the specified resource hashtable, filtered + * so that only two letter strings are returned. + * + * @param tableName the name of the table from which to retrieve the keys. + * @return an array of two-letter strings. + */ + /*private static String[] getISOStrings(String tableName) + { + int count = 0; + ResourceBundle bundle = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation"); + Enumeration e = bundle.getKeys(); + ArrayList tempList = new ArrayList(); + + while (e.hasMoreElements()) + { + String key = (String) e.nextElement(); + + if (key.startsWith(tableName + ".")) + { + String str = key.substring(tableName.length() + 1); + + if (str.length() == 2 + && Character.isLetter(str.charAt(0)) + && Character.isLetter(str.charAt(1))) + { + tempList.add(str); + ++count; + } + } + } + + String[] strings = new String[count]; + + for (int a = 0; a < count; ++a) + strings[a] = (String) tempList.get(a); + + return strings; + }*/ + + /** + * Returns the language code of this locale. Some language codes have changed + * as ISO 639 has evolved; this returns the old name, even if you built + * the locale with the new one. + * + * @return language code portion of this locale, or an empty String + */ + public String getLanguage() + { + return language; + } + + /** + * Returns the country code of this locale. + * + * @return country code portion of this locale, or an empty String + */ + public String getCountry() + { + return country; + } + + /** + * Returns the variant code of this locale. + * + * @return the variant code portion of this locale, or an empty String + */ + public String getVariant() + { + return variant; + } + + /** + * Gets the string representation of the current locale. This consists of + * the language, the country, and the variant, separated by an underscore. + * The variant is listed only if there is a language or country. Examples: + * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC". + * + * @return the string representation of this Locale + * @see #getDisplayName() + */ + /*public String toString() + { + if (language.length() == 0 && country.length() == 0) + return ""; + else if (country.length() == 0 && variant.length() == 0) + return language; + CPStringBuilder result = new CPStringBuilder(language); + result.append('_').append(country); + if (variant.length() != 0) + result.append('_').append(variant); + return result.toString(); + }*/ + + /** + * Returns the three-letter ISO language abbrevation of this locale. + * + * @throws MissingResourceException if the three-letter code is not known + */ + public String getISO3Language() + { + // We know all strings are interned so we can use '==' for better performance. + if (language == "") + return ""; + int index + = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da," + + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw," + + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn," + + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne," + + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk," + + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr," + + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu") + .indexOf(language); + + if (index % 3 != 0 || language.length() != 2) + throw new MissingResourceException + ("Can't find ISO3 language for " + language, + "java.util.Locale", language); + + // Don't read this aloud. These are the three letter language codes. + return + ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu" + + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv" + + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur" + + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm" + + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi" + + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd" + + "uzbvievolwolxhoyidyorzhazhozul") + .substring(index, index + 3); + } + + /** + * Returns the three-letter ISO country abbrevation of the locale. + * + * @throws MissingResourceException if the three-letter code is not known + */ + public String getISO3Country() + { + // We know all strings are interned so we can use '==' for better performance. + if (country == "") + return ""; + int index + = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF," + + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK," + + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER," + + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ," + + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT," + + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS," + + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV," + + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG," + + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH," + + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN," + + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF," + + "WS,YE,YT,YU,ZA,ZM,ZR,ZW") + .indexOf(country); + + if (index % 3 != 0 || country.length() != 2) + throw new MissingResourceException + ("Can't find ISO3 country for " + country, + "java.util.Locale", country); + + // Don't read this aloud. These are the three letter country codes. + return + ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR" + + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR" + + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN" + + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM" + + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ" + + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO" + + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER" + + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW" + + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP" + + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI" + + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE") + .substring(index, index + 3); + } + + /** + * Gets the country name suitable for display to the user, formatted + * for the default locale. This has the same effect as + *

+   * getDisplayLanguage(Locale.getDefault());
+   * 
+ * + * @return the language name of this locale localized to the default locale, + * with the ISO code as backup + */ + public String getDisplayLanguage() + { + return getDisplayLanguage(defaultLocale); + } + + /** + *

+ * Gets the name of the language specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is + * Locale.GERMANY, and the specified locale is Locale.UK, + * the result would be 'German'. Using the German locale would instead give + * 'Deutsch'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + *

+ * + *

+ * If the language is unspecified by this locale, then the empty string is + * returned. + *

+ * + * @param inLocale the locale to use for formatting the display string. + * @return the language name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + /*public String getDisplayLanguage(Locale inLocale) + { + if (language.isEmpty()) + return ""; + try + { + ResourceBundle res = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + inLocale, + ClassLoader.getSystemClassLoader()); + + return res.getString("languages." + language); + } + catch (MissingResourceException e) + {*/ + /* This means runtime support for the locale + * is not available, so we check providers. */ + /*} + for (LocaleNameProvider p : + ServiceLoader.load(LocaleNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(inLocale)) + { + String locLang = p.getDisplayLanguage(language, + inLocale); + if (locLang != null) + return locLang; + break; + } + } + } + if (inLocale.equals(Locale.ROOT)) // Base case + return language; + return getDisplayLanguage(LocaleHelper.getFallbackLocale(inLocale)); + }*/ + + /** + * Returns the country name of this locale localized to the + * default locale. If the localized is not found, the ISO code + * is returned. This has the same effect as + *
+   * getDisplayCountry(Locale.getDefault());
+   * 
+ * + * @return the country name of this locale localized to the given locale, + * with the ISO code as backup + */ + public String getDisplayCountry() + { + return null;//getDisplayCountry(defaultLocale); + } + + /** + *

+ * Gets the name of the country specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is + * Locale.GERMANY, and the specified locale is Locale.UK, + * the result would be 'Germany'. Using the German locale would instead give + * 'Deutschland'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + *

+ * + *

+ * If the country is unspecified by this locale, then the empty string is + * returned. + *

+ * + * @param inLocale the locale to use for formatting the display string. + * @return the country name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + /*public String getDisplayCountry(Locale inLocale) + { + if (country.isEmpty()) + return ""; + try + { + ResourceBundle res = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + inLocale, + ClassLoader.getSystemClassLoader()); + + return res.getString("territories." + country); + } + catch (MissingResourceException e) + {*/ + /* This means runtime support for the locale + * is not available, so we check providers. */ + /*} + for (LocaleNameProvider p : + ServiceLoader.load(LocaleNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(inLocale)) + { + String locCountry = p.getDisplayCountry(country, + inLocale); + if (locCountry != null) + return locCountry; + break; + } + } + } + if (inLocale.equals(Locale.ROOT)) // Base case + return country; + return getDisplayCountry(LocaleHelper.getFallbackLocale(inLocale)); + }*/ + + /** + * Returns the variant name of this locale localized to the + * default locale. If the localized is not found, the variant code + * itself is returned. This has the same effect as + *
+   * getDisplayVariant(Locale.getDefault());
+   * 
+ * + * @return the variant code of this locale localized to the given locale, + * with the ISO code as backup + */ + public String getDisplayVariant() + { + return getDisplayVariant(defaultLocale); + } + + + /** + *

+ * Gets the name of the variant specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is a revised + * variant, and the specified locale is Locale.UK, the result + * would be 'REVISED'. Using the German locale would instead give + * 'Revidiert'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + *

+ * + *

+ * If the variant is unspecified by this locale, then the empty string is + * returned. + *

+ * + * @param inLocale the locale to use for formatting the display string. + * @return the variant name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + /*public String getDisplayVariant(Locale inLocale) + { + if (variant.isEmpty()) + return ""; + try + { + ResourceBundle res = + ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + inLocale, + ClassLoader.getSystemClassLoader()); + + return res.getString("variants." + variant); + } + catch (MissingResourceException e) + {*/ + /* This means runtime support for the locale + * is not available, so we check providers. */ + /*} + for (LocaleNameProvider p : + ServiceLoader.load(LocaleNameProvider.class)) + { + for (Locale loc : p.getAvailableLocales()) + { + if (loc.equals(inLocale)) + { + String locVar = p.getDisplayVariant(variant, + inLocale); + if (locVar != null) + return locVar; + break; + } + } + } + if (inLocale.equals(Locale.ROOT)) // Base case + return country; + return getDisplayVariant(LocaleHelper.getFallbackLocale(inLocale)); + }*/ + + /** + * Gets all local components suitable for display to the user, formatted + * for the default locale. For the language component, getDisplayLanguage + * is called. For the country component, getDisplayCountry is called. + * For the variant set component, getDisplayVariant is called. + * + *

The returned String will be one of the following forms:
+ *

+   * language (country, variant)
+   * language (country)
+   * language (variant)
+   * country (variant)
+   * language
+   * country
+   * variant
+   * 
+ * + * @return String version of this locale, suitable for display to the user + */ + public String getDisplayName() + { + return getDisplayName(defaultLocale); + } + + /** + * Gets all local components suitable for display to the user, formatted + * for a specified locale. For the language component, + * getDisplayLanguage(Locale) is called. For the country component, + * getDisplayCountry(Locale) is called. For the variant set component, + * getDisplayVariant(Locale) is called. + * + *

The returned String will be one of the following forms:
+ *

+   * language (country, variant)
+   * language (country)
+   * language (variant)
+   * country (variant)
+   * language
+   * country
+   * variant
+   * 
+ * + * @param locale locale to use for formatting + * @return String version of this locale, suitable for display to the user + */ + /*public String getDisplayName(Locale locale) + { + CPStringBuilder result = new CPStringBuilder(); + int count = 0; + String[] delimiters = {"", " (", ","}; + if (language.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayLanguage(locale)); + } + if (country.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayCountry(locale)); + } + if (variant.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayVariant(locale)); + } + if (count > 1) + result.append(")"); + return result.toString(); + }*/ + + /** + * Does the same as Object.clone() but does not throw + * a CloneNotSupportedException. Why anyone would + * use this method is a secret to me, since this class is immutable. + * + * @return the clone + */ + public Object clone() + { + // This class is final, so no need to use native super.clone(). + return new Locale(language, country, variant); + } + + /** + * Return the hash code for this locale. The hashcode is the logical + * xor of the hash codes of the language, the country and the variant. + * The hash code is precomputed, since Locales are often + * used in hash tables. + * + * @return the hashcode + */ + public int hashCode() + { + return hashcode; + } + + /** + * Compares two locales. To be equal, obj must be a Locale with the same + * language, country, and variant code. + * + * @param obj the other locale + * @return true if obj is equal to this + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof Locale)) + return false; + Locale l = (Locale) obj; + + return (language == l.language + && country == l.country + && variant == l.variant); + } + + /** + * Write the locale to an object stream. + * + * @param s the stream to write to + * @throws IOException if the write fails + * @serialData The first three fields are Strings representing language, + * country, and variant. The fourth field is a placeholder for + * the cached hashcode, but this is always written as -1, and + * recomputed when reading it back. + */ + /*private void writeObject(ObjectOutputStream s) + throws IOException + { + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("hashcode", -1); + s.defaultWriteObject(); + }*/ + + /** + * Reads a locale from the input stream. + * + * @param s the stream to read from + * @throws IOException if reading fails + * @throws ClassNotFoundException if reading fails + * @serialData the hashCode is always invalid and must be recomputed + */ + /*private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + }*/ +} // class Locale diff --git a/Robust/src/ClassLibrary/MGC/gnu/MPN.java b/Robust/src/ClassLibrary/MGC/gnu/MPN.java new file mode 100644 index 00000000..8b6717eb --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/MPN.java @@ -0,0 +1,771 @@ +/* gnu.java.math.MPN + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +// Included from Kawa 1.6.62 with permission of the author, +// Per Bothner . + +//package gnu.java.math; + +/** This contains various low-level routines for unsigned bigints. + * The interfaces match the mpn interfaces in gmp, + * so it should be easy to replace them with fast native functions + * that are trivial wrappers around the mpn_ functions in gmp + * (at least on platforms that use 32-bit "limbs"). + */ + +public class MPN +{ + /** Add x[0:size-1] and y, and write the size least + * significant words of the result to dest. + * Return carry, either 0 or 1. + * All values are unsigned. + * This is basically the same as gmp's mpn_add_1. */ + public static int add_1 (int[] dest, int[] x, int size, int y) + { + long carry = (long) y & 0xffffffffL; + for (int i = 0; i < size; i++) + { + carry += ((long) x[i] & 0xffffffffL); + dest[i] = (int) carry; + carry >>= 32; + } + return (int) carry; + } + + /** Add x[0:len-1] and y[0:len-1] and write the len least + * significant words of the result to dest[0:len-1]. + * All words are treated as unsigned. + * @return the carry, either 0 or 1 + * This function is basically the same as gmp's mpn_add_n. + */ + public static int add_n (int dest[], int[] x, int[] y, int len) + { + long carry = 0; + for (int i = 0; i < len; i++) + { + carry += ((long) x[i] & 0xffffffffL) + + ((long) y[i] & 0xffffffffL); + dest[i] = (int) carry; + carry >>>= 32; + } + return (int) carry; + } + + /** Subtract Y[0:size-1] from X[0:size-1], and write + * the size least significant words of the result to dest[0:size-1]. + * Return borrow, either 0 or 1. + * This is basically the same as gmp's mpn_sub_n function. + */ + + public static int sub_n (int[] dest, int[] X, int[] Y, int size) + { + int cy = 0; + for (int i = 0; i < size; i++) + { + int y = Y[i]; + int x = X[i]; + y += cy; /* add previous carry to subtrahend */ + // Invert the high-order bit, because: (unsigned) X > (unsigned) Y + // iff: (int) (X^0x80000000) > (int) (Y^0x80000000). + cy = (y^0x80000000) < (cy^0x80000000) ? 1 : 0; + y = x - y; + cy += (y^0x80000000) > (x ^ 0x80000000) ? 1 : 0; + dest[i] = y; + } + return cy; + } + + /** Multiply x[0:len-1] by y, and write the len least + * significant words of the product to dest[0:len-1]. + * Return the most significant word of the product. + * All values are treated as if they were unsigned + * (i.e. masked with 0xffffffffL). + * OK if dest==x (not sure if this is guaranteed for mpn_mul_1). + * This function is basically the same as gmp's mpn_mul_1. + */ + + public static int mul_1 (int[] dest, int[] x, int len, int y) + { + long yword = (long) y & 0xffffffffL; + long carry = 0; + for (int j = 0; j < len; j++) + { + carry += ((long) x[j] & 0xffffffffL) * yword; + dest[j] = (int) carry; + carry >>>= 32; + } + return (int) carry; + } + + /** + * Multiply x[0:xlen-1] and y[0:ylen-1], and + * write the result to dest[0:xlen+ylen-1]. + * The destination has to have space for xlen+ylen words, + * even if the result might be one limb smaller. + * This function requires that xlen >= ylen. + * The destination must be distinct from either input operands. + * All operands are unsigned. + * This function is basically the same gmp's mpn_mul. */ + + public static void mul (int[] dest, + int[] x, int xlen, + int[] y, int ylen) + { + dest[xlen] = MPN.mul_1 (dest, x, xlen, y[0]); + + for (int i = 1; i < ylen; i++) + { + long yword = (long) y[i] & 0xffffffffL; + long carry = 0; + for (int j = 0; j < xlen; j++) + { + carry += ((long) x[j] & 0xffffffffL) * yword + + ((long) dest[i+j] & 0xffffffffL); + dest[i+j] = (int) carry; + carry >>>= 32; + } + dest[i+xlen] = (int) carry; + } + } + + /* Divide (unsigned long) N by (unsigned int) D. + * Returns (remainder << 32)+(unsigned int)(quotient). + * Assumes (unsigned int)(N>>32) < (unsigned int)D. + * Code transcribed from gmp-2.0's mpn_udiv_w_sdiv function. + */ + public static long udiv_qrnnd (long N, int D) + { + long q, r; + long a1 = N >>> 32; + long a0 = N & 0xffffffffL; + if (D >= 0) + { + if (a1 < ((D - a1 - (a0 >>> 31)) & 0xffffffffL)) + { + /* dividend, divisor, and quotient are nonnegative */ + q = N / D; + r = N % D; + } + else + { + /* Compute c1*2^32 + c0 = a1*2^32 + a0 - 2^31*d */ + long c = N - ((long) D << 31); + /* Divide (c1*2^32 + c0) by d */ + q = c / D; + r = c % D; + /* Add 2^31 to quotient */ + q += 1 << 31; + } + } + else + { + long b1 = D >>> 1; /* d/2, between 2^30 and 2^31 - 1 */ + //long c1 = (a1 >> 1); /* A/2 */ + //int c0 = (a1 << 31) + (a0 >> 1); + long c = N >>> 1; + if (a1 < b1 || (a1 >> 1) < b1) + { + if (a1 < b1) + { + q = c / b1; + r = c % b1; + } + else /* c1 < b1, so 2^31 <= (A/2)/b1 < 2^32 */ + { + c = ~(c - (b1 << 32)); + q = c / b1; /* (A/2) / (d/2) */ + r = c % b1; + q = (~q) & 0xffffffffL; /* (A/2)/b1 */ + r = (b1 - 1) - r; /* r < b1 => new r >= 0 */ + } + r = 2 * r + (a0 & 1); + if ((D & 1) != 0) + { + if (r >= q) { + r = r - q; + } else if (q - r <= ((long) D & 0xffffffffL)) { + r = r - q + D; + q -= 1; + } else { + r = r - q + D + D; + q -= 2; + } + } + } + else /* Implies c1 = b1 */ + { /* Hence a1 = d - 1 = 2*b1 - 1 */ + if (a0 >= ((long)(-D) & 0xffffffffL)) + { + q = -1; + r = a0 + D; + } + else + { + q = -2; + r = a0 + D + D; + } + } + } + + return (r << 32) | (q & 0xFFFFFFFFl); + } + + /** Divide divident[0:len-1] by (unsigned int)divisor. + * Write result into quotient[0:len-1. + * Return the one-word (unsigned) remainder. + * OK for quotient==dividend. + */ + + public static int divmod_1 (int[] quotient, int[] dividend, + int len, int divisor) + { + int i = len - 1; + long r = dividend[i]; + if ((r & 0xffffffffL) >= ((long)divisor & 0xffffffffL)) + r = 0; + else + { + quotient[i--] = 0; + r <<= 32; + } + + for (; i >= 0; i--) + { + int n0 = dividend[i]; + r = (r & ~0xffffffffL) | (n0 & 0xffffffffL); + r = udiv_qrnnd (r, divisor); + quotient[i] = (int) r; + } + return (int)(r >> 32); + } + + /* Subtract x[0:len-1]*y from dest[offset:offset+len-1]. + * All values are treated as if unsigned. + * @return the most significant word of + * the product, minus borrow-out from the subtraction. + */ + public static int submul_1 (int[] dest, int offset, int[] x, int len, int y) + { + long yl = (long) y & 0xffffffffL; + int carry = 0; + int j = 0; + do + { + long prod = ((long) x[j] & 0xffffffffL) * yl; + int prod_low = (int) prod; + int prod_high = (int) (prod >> 32); + prod_low += carry; + // Invert the high-order bit, because: (unsigned) X > (unsigned) Y + // iff: (int) (X^0x80000000) > (int) (Y^0x80000000). + carry = ((prod_low ^ 0x80000000) < (carry ^ 0x80000000) ? 1 : 0) + + prod_high; + int x_j = dest[offset+j]; + prod_low = x_j - prod_low; + if ((prod_low ^ 0x80000000) > (x_j ^ 0x80000000)) + carry++; + dest[offset+j] = prod_low; + } + while (++j < len); + return carry; + } + + /** Divide zds[0:nx] by y[0:ny-1]. + * The remainder ends up in zds[0:ny-1]. + * The quotient ends up in zds[ny:nx]. + * Assumes: nx>ny. + * (int)y[ny-1] < 0 (i.e. most significant bit set) + */ + + public static void divide (int[] zds, int nx, int[] y, int ny) + { + // This is basically Knuth's formulation of the classical algorithm, + // but translated from in scm_divbigbig in Jaffar's SCM implementation. + + // Correspondance with Knuth's notation: + // Knuth's u[0:m+n] == zds[nx:0]. + // Knuth's v[1:n] == y[ny-1:0] + // Knuth's n == ny. + // Knuth's m == nx-ny. + // Our nx == Knuth's m+n. + + // Could be re-implemented using gmp's mpn_divrem: + // zds[nx] = mpn_divrem (&zds[ny], 0, zds, nx, y, ny). + + int j = nx; + do + { // loop over digits of quotient + // Knuth's j == our nx-j. + // Knuth's u[j:j+n] == our zds[j:j-ny]. + int qhat; // treated as unsigned + if (zds[j]==y[ny-1]) + qhat = -1; // 0xffffffff + else + { + long w = (((long)(zds[j])) << 32) + ((long)zds[j-1] & 0xffffffffL); + qhat = (int) udiv_qrnnd (w, y[ny-1]); + } + if (qhat != 0) + { + int borrow = submul_1 (zds, j - ny, y, ny, qhat); + int save = zds[j]; + long num = ((long)save&0xffffffffL) - ((long)borrow&0xffffffffL); + while (num != 0) + { + qhat--; + long carry = 0; + for (int i = 0; i < ny; i++) + { + carry += ((long) zds[j-ny+i] & 0xffffffffL) + + ((long) y[i] & 0xffffffffL); + zds[j-ny+i] = (int) carry; + carry >>>= 32; + } + zds[j] += carry; + num = carry - 1; + } + } + zds[j] = qhat; + } while (--j >= ny); + } + + /** Number of digits in the conversion base that always fits in a word. + * For example, for base 10 this is 9, since 10**9 is the + * largest number that fits into a words (assuming 32-bit words). + * This is the same as gmp's __mp_bases[radix].chars_per_limb. + * @param radix the base + * @return number of digits */ + public static int chars_per_word (int radix) + { + if (radix < 10) + { + if (radix < 8) + { + if (radix <= 2) + return 32; + else if (radix == 3) + return 20; + else if (radix == 4) + return 16; + else + return 18 - radix; + } + else + return 10; + } + else if (radix < 12) + return 9; + else if (radix <= 16) + return 8; + else if (radix <= 23) + return 7; + else if (radix <= 40) + return 6; + // The following are conservative, but we don't care. + else if (radix <= 256) + return 4; + else + return 1; + } + + /** Count the number of leading zero bits in an int. */ + public static int count_leading_zeros (int i) + { + if (i == 0) + return 32; + int count = 0; + for (int k = 16; k > 0; k = k >> 1) { + int j = i >>> k; + if (j == 0) + count += k; + else + i = j; + } + return count; + } + + public static int set_str (int dest[], byte[] str, int str_len, int base) + { + int size = 0; + if ((base & (base - 1)) == 0) + { + // The base is a power of 2. Read the input string from + // least to most significant character/digit. */ + + int next_bitpos = 0; + int bits_per_indigit = 0; + for (int i = base; (i >>= 1) != 0; ) bits_per_indigit++; + int res_digit = 0; + + for (int i = str_len; --i >= 0; ) + { + int inp_digit = str[i]; + res_digit |= inp_digit << next_bitpos; + next_bitpos += bits_per_indigit; + if (next_bitpos >= 32) + { + dest[size++] = res_digit; + next_bitpos -= 32; + res_digit = inp_digit >> (bits_per_indigit - next_bitpos); + } + } + + if (res_digit != 0) + dest[size++] = res_digit; + } + else + { + // General case. The base is not a power of 2. + int indigits_per_limb = MPN.chars_per_word (base); + int str_pos = 0; + + while (str_pos < str_len) + { + int chunk = str_len - str_pos; + if (chunk > indigits_per_limb) + chunk = indigits_per_limb; + int res_digit = str[str_pos++]; + int big_base = base; + + while (--chunk > 0) + { + res_digit = res_digit * base + str[str_pos++]; + big_base *= base; + } + + int cy_limb; + if (size == 0) + cy_limb = res_digit; + else + { + cy_limb = MPN.mul_1 (dest, dest, size, big_base); + cy_limb += MPN.add_1 (dest, dest, size, res_digit); + } + if (cy_limb != 0) + dest[size++] = cy_limb; + } + } + return size; + } + + /** Compare x[0:size-1] with y[0:size-1], treating them as unsigned integers. + * @result -1, 0, or 1 depending on if x<y, x==y, or x>y. + * This is basically the same as gmp's mpn_cmp function. + */ + public static int cmp (int[] x, int[] y, int size) + { + while (--size >= 0) + { + int x_word = x[size]; + int y_word = y[size]; + if (x_word != y_word) + { + // Invert the high-order bit, because: + // (unsigned) X > (unsigned) Y iff + // (int) (X^0x80000000) > (int) (Y^0x80000000). + return (x_word ^ 0x80000000) > (y_word ^0x80000000) ? 1 : -1; + } + } + return 0; + } + + /** + * Compare x[0:xlen-1] with y[0:ylen-1], treating them as unsigned integers. + * + * @return -1, 0, or 1 depending on if x<y, x==y, or x>y. + */ + public static int cmp (int[] x, int xlen, int[] y, int ylen) + { + return xlen > ylen ? 1 : xlen < ylen ? -1 : cmp (x, y, xlen); + } + + /** + * Shift x[x_start:x_start+len-1] count bits to the "right" + * (i.e. divide by 2**count). + * Store the len least significant words of the result at dest. + * The bits shifted out to the right are returned. + * OK if dest==x. + * Assumes: 0 < count < 32 + */ + public static int rshift (int[] dest, int[] x, int x_start, + int len, int count) + { + int count_2 = 32 - count; + int low_word = x[x_start]; + int retval = low_word << count_2; + int i = 1; + for (; i < len; i++) + { + int high_word = x[x_start+i]; + dest[i-1] = (low_word >>> count) | (high_word << count_2); + low_word = high_word; + } + dest[i-1] = low_word >>> count; + return retval; + } + + /** + * Shift x[x_start:x_start+len-1] count bits to the "right" + * (i.e. divide by 2**count). + * Store the len least significant words of the result at dest. + * OK if dest==x. + * Assumes: 0 <= count < 32 + * Same as rshift, but handles count==0 (and has no return value). + */ + public static void rshift0 (int[] dest, int[] x, int x_start, + int len, int count) + { + if (count > 0) + rshift(dest, x, x_start, len, count); + else + for (int i = 0; i < len; i++) + dest[i] = x[i + x_start]; + } + + /** Return the long-truncated value of right shifting. + * @param x a two's-complement "bignum" + * @param len the number of significant words in x + * @param count the shift count + * @return (long)(x[0..len-1] >> count). + */ + public static long rshift_long (int[] x, int len, int count) + { + int wordno = count >> 5; + count &= 31; + int sign = x[len-1] < 0 ? -1 : 0; + int w0 = wordno >= len ? sign : x[wordno]; + wordno++; + int w1 = wordno >= len ? sign : x[wordno]; + if (count != 0) + { + wordno++; + int w2 = wordno >= len ? sign : x[wordno]; + w0 = (w0 >>> count) | (w1 << (32-count)); + w1 = (w1 >>> count) | (w2 << (32-count)); + } + return ((long)w1 << 32) | ((long)w0 & 0xffffffffL); + } + + /* Shift x[0:len-1] left by count bits, and store the len least + * significant words of the result in dest[d_offset:d_offset+len-1]. + * Return the bits shifted out from the most significant digit. + * Assumes 0 < count < 32. + * OK if dest==x. + */ + + public static int lshift (int[] dest, int d_offset, + int[] x, int len, int count) + { + int count_2 = 32 - count; + int i = len - 1; + int high_word = x[i]; + int retval = high_word >>> count_2; + d_offset++; + while (--i >= 0) + { + int low_word = x[i]; + dest[d_offset+i] = (high_word << count) | (low_word >>> count_2); + high_word = low_word; + } + dest[d_offset+i] = high_word << count; + return retval; + } + + /** Return least i such that word & (1<<i). Assumes word!=0. */ + + public static int findLowestBit (int word) + { + int i = 0; + while ((word & 0xF) == 0) + { + word >>= 4; + i += 4; + } + if ((word & 3) == 0) + { + word >>= 2; + i += 2; + } + if ((word & 1) == 0) + i += 1; + return i; + } + + /** Return least i such that words & (1<<i). Assumes there is such an i. */ + + public static int findLowestBit (int[] words) + { + for (int i = 0; ; i++) + { + if (words[i] != 0) + return 32 * i + findLowestBit (words[i]); + } + } + + /** Calculate Greatest Common Divisior of x[0:len-1] and y[0:len-1]. + * Assumes both arguments are non-zero. + * Leaves result in x, and returns len of result. + * Also destroys y (actually sets it to a copy of the result). */ + + public static int gcd (int[] x, int[] y, int len) + { + int i, word; + // Find sh such that both x and y are divisible by 2**sh. + for (i = 0; ; i++) + { + word = x[i] | y[i]; + if (word != 0) + { + // Must terminate, since x and y are non-zero. + break; + } + } + int initShiftWords = i; + int initShiftBits = findLowestBit (word); + // Logically: sh = initShiftWords * 32 + initShiftBits + + // Temporarily devide both x and y by 2**sh. + len -= initShiftWords; + MPN.rshift0 (x, x, initShiftWords, len, initShiftBits); + MPN.rshift0 (y, y, initShiftWords, len, initShiftBits); + + int[] odd_arg; /* One of x or y which is odd. */ + int[] other_arg; /* The other one can be even or odd. */ + if ((x[0] & 1) != 0) + { + odd_arg = x; + other_arg = y; + } + else + { + odd_arg = y; + other_arg = x; + } + + for (;;) + { + // Shift other_arg until it is odd; this doesn't + // affect the gcd, since we divide by 2**k, which does not + // divide odd_arg. + for (i = 0; other_arg[i] == 0; ) i++; + if (i > 0) + { + int j; + for (j = 0; j < len-i; j++) + other_arg[j] = other_arg[j+i]; + for ( ; j < len; j++) + other_arg[j] = 0; + } + i = findLowestBit(other_arg[0]); + if (i > 0) + MPN.rshift (other_arg, other_arg, 0, len, i); + + // Now both odd_arg and other_arg are odd. + + // Subtract the smaller from the larger. + // This does not change the result, since gcd(a-b,b)==gcd(a,b). + i = MPN.cmp(odd_arg, other_arg, len); + if (i == 0) + break; + if (i > 0) + { // odd_arg > other_arg + MPN.sub_n (odd_arg, odd_arg, other_arg, len); + // Now odd_arg is even, so swap with other_arg; + int[] tmp = odd_arg; odd_arg = other_arg; other_arg = tmp; + } + else + { // other_arg > odd_arg + MPN.sub_n (other_arg, other_arg, odd_arg, len); + } + while (odd_arg[len-1] == 0 && other_arg[len-1] == 0) + len--; + } + if (initShiftWords + initShiftBits > 0) + { + if (initShiftBits > 0) + { + int sh_out = MPN.lshift (x, initShiftWords, x, len, initShiftBits); + if (sh_out != 0) + x[(len++)+initShiftWords] = sh_out; + } + else + { + for (i = len; --i >= 0;) + x[i+initShiftWords] = x[i]; + } + for (i = initShiftWords; --i >= 0; ) + x[i] = 0; + len += initShiftWords; + } + return len; + } + + public static int intLength (int i) + { + return 32 - count_leading_zeros (i < 0 ? ~i : i); + } + + /** Calcaulte the Common Lisp "integer-length" function. + * Assumes input is canonicalized: len==BigInteger.wordsNeeded(words,len) */ + public static int intLength (int[] words, int len) + { + len--; + return intLength (words[len]) + 32 * len; + } + + /* DEBUGGING: + public static void dprint (BigInteger x) + { + if (x.words == null) + System.err.print(Long.toString((long) x.ival & 0xffffffffL, 16)); + else + dprint (System.err, x.words, x.ival); + } + public static void dprint (int[] x) { dprint (System.err, x, x.length); } + public static void dprint (int[] x, int len) { dprint (System.err, x, len); } + public static void dprint (java.io.PrintStream ps, int[] x, int len) + { + ps.print('('); + for (int i = 0; i < len; i++) + { + if (i > 0) + ps.print (' '); + ps.print ("#x" + Long.toString ((long) x[i] & 0xffffffffL, 16)); + } + ps.print(')'); + } + */ +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/PrintStream.java b/Robust/src/ClassLibrary/MGC/gnu/PrintStream.java new file mode 100644 index 00000000..85b5b47a --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/PrintStream.java @@ -0,0 +1,675 @@ +/* PrintStream.java -- OutputStream for printing output + Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +//package java.io; + +/*import java.util.Locale; +import java.util.Formatter; + +import gnu.classpath.SystemProperties; +*/ +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Believed complete and correct to 1.3 + */ + +/** + * This class prints Java primitive values and object to a stream as + * text. None of the methods in this class throw an exception. However, + * errors can be detected by calling the checkError() method. + * Additionally, this stream can be designated as "autoflush" when + * created so that any writes are automatically flushed to the underlying + * output sink when the current line is terminated. + *

+ * This class converts char's into byte's using the system default encoding. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public class PrintStream extends FilterOutputStream //implements Appendable +{ + /* Notice the implementation is quite similar to OutputStreamWriter. + * This leads to some minor duplication, because neither inherits + * from the other, and we want to maximize performance. */ + + // Line separator string. + private static final char[] line_separator + = {}/*SystemProperties.getProperty("line.separator", "\n").toCharArray()*/; + + /** + * Encoding name + */ + private final String encoding; + + /** + * This boolean indicates whether or not an error has ever occurred + * on this stream. + */ + private boolean error_occurred = false; + + /** + * This is true if auto-flush is enabled, + * false otherwise + */ + private final boolean auto_flush; + + /** + * This method initializes a new PrintStream object to write + * to the specified output File. Doesn't autoflush. + * + * @param file The File to write to. + * @throws FileNotFoundException if an error occurs while opening the file. + * + * @since 1.5 + */ + public PrintStream (File file) + //throws FileNotFoundException + { + this (new FileOutputStream(file), false); + } + + /** + * This method initializes a new PrintStream object to write + * to the specified output File. Doesn't autoflush. + * + * @param file The File to write to. + * @param encoding The name of the character encoding to use for this + * object. + * @throws FileNotFoundException If an error occurs while opening the file. + * @throws UnsupportedEncodingException If the charset specified by + * encoding is invalid. + * + * @since 1.5 + */ + public PrintStream (File file, String encoding) + //throws FileNotFoundException,UnsupportedEncodingException + { + this (new FileOutputStream(file), false, encoding); + } + + /** + * This method initializes a new PrintStream object to write + * to the specified output File. Doesn't autoflush. + * + * @param fileName The name of the File to write to. + * @throws FileNotFoundException if an error occurs while opening the file, + * + * @since 1.5 + */ + public PrintStream (String fileName) + //throws FileNotFoundException + { + this (new FileOutputStream(new File(fileName)), false); + } + + /** + * This method initializes a new PrintStream object to write + * to the specified output File. Doesn't autoflush. + * + * @param fileName The name of the File to write to. + * @param encoding The name of the character encoding to use for this + * object. + * @throws FileNotFoundException if an error occurs while opening the file. + * @throws UnsupportedEncodingException If the charset specified by + * encoding is invalid. + * + * @since 1.5 + */ + public PrintStream (String fileName, String encoding) + //throws FileNotFoundException,UnsupportedEncodingException + { + this (new FileOutputStream(new File(fileName)), false, encoding); + } + + /** + * This method initializes a new PrintStream object to write + * to the specified output sink. Doesn't autoflush. + * + * @param out The OutputStream to write to. + */ + public PrintStream (OutputStream out) + { + this (out, false); + } + + /** + * This method initializes a new PrintStream object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every print or println call, when the + * write methods with array arguments are called, or when a + * single new-line character is written. + *

+ * + * @param out The OutputStream to write to. + * @param auto_flush true to flush the stream after every + * line, false otherwise + */ + public PrintStream (OutputStream out, boolean auto_flush) + { + super (out); + /*String encoding; + try { + encoding = SystemProperties.getProperty("file.encoding"); + } catch (SecurityException e){ + encoding = "ISO8859_1"; + } catch (IllegalArgumentException e){ + encoding = "ISO8859_1"; + } catch (NullPointerException e){ + encoding = "ISO8859_1"; + }*/ + this.encoding = "ISO8859_1"; //encoding; + this.auto_flush = auto_flush; + } + + /** + * This method initializes a new PrintStream object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every print or println call, when the + * write methods with array arguments are called, or when a + * single new-line character is written. + *

+ * + * @param out The OutputStream to write to. + * @param auto_flush true to flush the stream after every + * line, false otherwise + * @param encoding The name of the character encoding to use for this + * object. + */ + public PrintStream (OutputStream out, boolean auto_flush, String encoding) + //throws UnsupportedEncodingException + { + super (out); + + new String(new byte[]{0}, encoding); // check if encoding is supported + this.encoding = encoding; + this.auto_flush = auto_flush; + } + + /** + * This method checks to see if an error has occurred on this stream. Note + * that once an error has occurred, this method will continue to report + * true forever for this stream. Before checking for an + * error condition, this method flushes the stream. + * + * @return true if an error has occurred, + * false otherwise + */ + public boolean checkError () + { + flush (); + return error_occurred; + } + + /** + * This method can be called by subclasses to indicate that an error + * has occurred and should be reported by checkError. + */ + protected void setError () + { + error_occurred = true; + } + + /** + * This method closes this stream and all underlying streams. + */ + public void close () + { + /*try + { + flush(); + out.close(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + }*/ + } + + /** + * This method flushes any buffered bytes to the underlying stream and + * then flushes that stream as well. + */ + public void flush () + { + /*try + { + out.flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + }*/ + } + + private synchronized void print (String str, boolean println) + { + /*try + { + writeChars(str, 0, str.length()); + if (println) + writeChars(line_separator, 0, line_separator.length); + if (auto_flush) + flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + }*/ + } + + private synchronized void print (char[] chars, int pos, int len, + boolean println) + { + /*try + { + writeChars(chars, pos, len); + if (println) + writeChars(line_separator, 0, line_separator.length); + if (auto_flush) + flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + }*/ + } + + private void writeChars(char[] buf, int offset, int count) + //throws IOException + { + /*byte[] bytes = (new String(buf, offset, count)).getBytes(encoding); + out.write(bytes, 0, bytes.length);*/ + } + + private void writeChars(String str, int offset, int count) + //throws IOException + { + /*byte[] bytes = str.substring(offset, offset+count).getBytes(encoding); + out.write(bytes, 0, bytes.length);*/ + } + + /** + * This methods prints a boolean value to the stream. true + * values are printed as "true" and false values are printed + * as "false". + * + * @param bool The boolean value to print + */ + public void print (boolean bool) + { + print(String.valueOf(bool), false); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param inum The int value to be printed + */ + public void print (int inum) + { + print(String.valueOf(inum), false); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param lnum The long value to be printed + */ + public void print (long lnum) + { + print(String.valueOf(lnum), false); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param fnum The float value to be printed + */ + public void print (float fnum) + { + print(String.valueOf(fnum), false); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the String.valueOf() method. + * + * @param dnum The double value to be printed + */ + public void print (double dnum) + { + print(String.valueOf(dnum), false); + } + + /** + * This method prints an Object to the stream. The actual + * value printed is determined by calling the String.valueOf() + * method. + * + * @param obj The Object to print. + */ + public void print (Object obj) + { + print(obj == null ? "null" : obj.toString(), false); + } + + /** + * This method prints a String to the stream. The actual + * value printed depends on the system default encoding. + * + * @param str The String to print. + */ + public void print (String str) + { + print(str == null ? "null" : str, false); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + * + * @param ch The char value to be printed + */ + public synchronized void print (char ch) + { + print(new char[]{ch}, 0, 1, false); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + * + * @param charArray The array of characters to print. + */ + public void print (char[] charArray) + { + print(charArray, 0, charArray.length, false); + } + + /** + * This method prints a line separator sequence to the stream. The value + * printed is determined by the system property

line.separator + * and is not necessarily the Unix '\n' newline character. + */ + /*public void println () + { + print(line_separator, 0, line_separator.length, false); + }*/ + + /** + * This methods prints a boolean value to the stream. true + * values are printed as "true" and false values are printed + * as "false". + *

+ * This method prints a line termination sequence after printing the value. + * + * @param bool The boolean value to print + */ + public void println (boolean bool) + { + print(String.valueOf(bool), true); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the String.valueOf() method. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param inum The int value to be printed + */ + public void println (int inum) + { + print(String.valueOf(inum), true); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the String.valueOf() method. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param lnum The long value to be printed + */ + public void println (long lnum) + { + print(String.valueOf(lnum), true); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the String.valueOf() method. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param fnum The float value to be printed + */ + public void println (float fnum) + { + print(String.valueOf(fnum), true); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the String.valueOf() method. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param dnum The double value to be printed + */ + public void println (double dnum) + { + print(String.valueOf(dnum), true); + } + + /** + * This method prints an Object to the stream. The actual + * value printed is determined by calling the String.valueOf() + * method. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param obj The Object to print. + */ + public void println (Object obj) + { + print(obj == null ? "null" : obj.toString(), true); + } + + /** + * This method prints a String to the stream. The actual + * value printed depends on the system default encoding. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param str The String to print. + */ + public void println (String str) + { + print (str == null ? "null" : str, true); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param ch The char value to be printed + */ + public synchronized void println (char ch) + { + print(new char[]{ch}, 0, 1, true); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + *

+ * This method prints a line termination sequence after printing the value. + * + * @param charArray The array of characters to print. + */ + public void println (char[] charArray) + { + print(charArray, 0, charArray.length, true); + } + + /** + * This method writes a byte of data to the stream. If auto-flush is + * enabled, printing a newline character will cause the stream to be + * flushed after the character is written. + * + * @param oneByte The byte to be written + */ + public void write (int oneByte) + { + /*try + { + out.write (oneByte & 0xff); + + if (auto_flush && (oneByte == '\n')) + flush (); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread ().interrupt (); + } + catch (IOException e) + { + setError (); + }*/ + } + + /** + * This method writes len bytes from the specified array + * starting at index offset into the array. + * + * @param buffer The array of bytes to write + * @param offset The index into the array to start writing from + * @param len The number of bytes to write + */ + public void write (byte[] buffer, int offset, int len) + { + /*try + { + out.write (buffer, offset, len); + + if (auto_flush) + flush (); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread ().interrupt (); + } + catch (IOException e) + { + setError (); + }*/ + } + + /** @since 1.5 */ + public PrintStream append(char c) + { + print(c); + return this; + } + + /** @since 1.5 */ + /*public PrintStream append(CharSequence cs) + { + print(cs == null ? "null" : cs.toString()); + return this; + }*/ + + /** @since 1.5 */ + /*public PrintStream append(CharSequence cs, int start, int end) + { + print(cs == null ? "null" : cs.subSequence(start, end).toString()); + return this; + }*/ + + /** @since 1.5 */ + /*public PrintStream printf(String format, Object... args) + { + return this; //format(format, args); + }*/ + + /** @since 1.5 */ + /*public PrintStream printf(Locale locale, String format, Object... args) + { + return format(locale, format, args); + }*/ + + /** @since 1.5 */ + /*public PrintStream format(String format, Object... args) + { + return this; //format(Locale.getDefault(), format, args); + }*/ + + /** @since 1.5 */ + /*public PrintStream format(Locale locale, String format, Object... args) + { + Formatter f = new Formatter(this, locale); + f.format(format, args); + return this; + }*/ +} // class PrintStream diff --git a/Robust/src/ClassLibrary/MGC/gnu/Reader.java b/Robust/src/ClassLibrary/MGC/gnu/Reader.java new file mode 100644 index 00000000..ef2268f2 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Reader.java @@ -0,0 +1,288 @@ +/* Reader.java -- base class of classes that read input as a stream of chars + Copyright (C) 1998, 1999, 2000, 2003, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +//package java.io; + +//import java.nio.CharBuffer; + +///* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This abstract class forms the base of the hierarchy of classes that read + * input as a stream of characters. It provides a common set of methods for + * reading characters from streams. Subclasses implement and extend these + * methods to read characters from a particular input source such as a file + * or network connection. + * + * @author Per Bothner (bothner@cygnus.com) + * @date April 21, 1998. + * @author Aaron M. Renn (arenn@urbanophile.com) + */ +public abstract class Reader //implements Closeable, Readable +{ + /** + * This is the Object used for synchronizing critical code + * sections. Subclasses should use this variable instead of a + * synchronized method or an explicit synchronization on this + */ + protected Object lock; + + /** + * Unitializes a Reader that will use the object + * itself for synchronization of critical code sections. + */ + protected Reader() + { + this.lock = this; + } + + /** + * Initializes a Reader that will use the specified + * Object for synchronization of critical code sections. + * + * @param lock The Object to use for synchronization + */ + protected Reader(Object lock) + { + this.lock = lock; + } + + /** + * Read chars from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index offset + * into the buffer and attempts to read len chars. This method + * can return before reading the number of chars requested. The actual + * number of chars read is returned as an int. A -1 is returned to indicate + * the end of the stream. + *

+ * This method will block until some data can be read. + *

+ * This method operates by calling the single char read() method + * in a loop until the desired number of chars are read. The read loop + * stops short if the end of the stream is encountered or if an IOException + * is encountered on any read operation except the first. If the first + * attempt to read a chars fails, the IOException is allowed to propagate + * upward. And subsequent IOException is caught and treated identically + * to an end of stream condition. Subclasses can (and should if possible) + * override this method to provide a more efficient implementation. + * + * @param buf The array into which the chars read should be stored + * @param offset The offset into the array to start storing chars + * @param count The requested number of chars to read + * + * @return The actual number of chars read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public /*abstract*/ int read(char buf[], int offset, int count) { + return -1; + } + //throws IOException; + + /** + * Reads chars from a stream and stores them into a caller + * supplied buffer. This method attempts to completely fill the buffer, + * but can return before doing so. The actual number of chars read is + * returned as an int. A -1 is returned to indicate the end of the stream. + *

+ * This method will block until some data can be read. + *

+ * This method operates by calling an overloaded read method like so: + * read(buf, 0, buf.length) + * + * @param buf The buffer into which the chars read will be stored. + * + * @return The number of chars read or -1 if end of stream. + * + * @exception IOException If an error occurs. + */ + public int read(char buf[]) //throws IOException + { + return read(buf, 0, buf.length); + } + + /** + * Reads an char from the input stream and returns it + * as an int in the range of 0-65535. This method also will return -1 if + * the end of the stream has been reached. + *

+ * This method will block until the char can be read. + * + * @return The char read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public int read() //throws IOException + { + char[] buf = new char[1]; + int count = read(buf, 0, 1); + return count > 0 ? buf[0] : -1; + } + + /** @since 1.5 */ + /*public int read(CharBuffer buffer) throws IOException + { + // We want to call put(), so we don't manipulate the CharBuffer + // directly. + int rem = buffer.remaining(); + char[] buf = new char[rem]; + int result = read(buf, 0, rem); + if (result != -1) + buffer.put(buf, 0, result); + return result; + }*/ + + /** + * Closes the stream. Any futher attempts to read from the + * stream may generate an IOException. + * + * @exception IOException If an error occurs + */ + public /*abstract*/ void close() {} //throws IOException; + + /** + * Returns a boolean that indicates whether the mark/reset + * methods are supported in this class. Those methods can be used to + * remember a specific point in the stream and reset the stream to that + * point. + *

+ * This method always returns false in this class, but + * subclasses can override this method to return true if they + * support mark/reset functionality. + * + * @return true if mark/reset functionality is supported, + * false otherwise + * + */ + public boolean markSupported() + { + return false; + } + + /** + * Marks a position in the input to which the stream can be + * "reset" by calling the reset() method. The parameter + * readlimit is the number of chars that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if mark() is called with a read limit of 10, then + * when 11 chars of data are read from the stream before the + * reset() method is called, then the mark is invalid and the + * stream object instance is not required to remember the mark. + * + * @param readLimit The number of chars that can be read before the mark + * becomes invalid + * + * @exception IOException If an error occurs such as mark not being + * supported for this class + */ + public void mark(int readLimit) //throws IOException + { + throw new Error/*IOException*/("mark not supported"); + } + + /** + * Resets a stream to the point where the mark() + * method was called. Any chars that were read after the mark point was + * set will be re-read during subsequent reads. + *

+ * This method always throws an IOException in this class, but subclasses + * can override this method if they provide mark/reset functionality. + * + * @exception IOException Always thrown for this class + */ + public void reset() //throws IOException + { + throw new Error/*IOException*/("reset not supported"); + } + + /** + * Determines whether or not this stream is ready to be + * read. If it returns false the stream may block if a + * read is attempted, but it is not guaranteed to do so. + *

+ * This method always returns false in this class + * + * @return true if the stream is ready to be read, + * false otherwise. + * + * @exception IOException If an error occurs + */ + public boolean ready() //throws IOException + { + return false; + } + + /** + * Skips the specified number of chars in the stream. It + * returns the actual number of chars skipped, which may be less than the + * requested amount. + *

+ * This method reads and discards chars into a 256 char array until the + * specified number of chars were skipped or until either the end of stream + * is reached or a read attempt returns a short count. Subclasses can + * override this method to provide a more efficient implementation where + * one exists. + * + * @param count The requested number of chars to skip + * + * @return The actual number of chars skipped. + * + * @exception IOException If an error occurs + */ + public long skip(long count) //throws IOException + { + if (count <= 0) + return 0; + int bsize = count > 1024 ? 1024 : (int) count; + char[] buffer = new char[bsize]; + long todo = count; + synchronized (lock) + { + while (todo > 0) + { + int skipped = read(buffer, 0, bsize > todo ? (int) todo : bsize); + if (skipped <= 0) + break; + todo -= skipped; + } + } + return count - todo; + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/RuntimeException.java b/Robust/src/ClassLibrary/MGC/gnu/RuntimeException.java new file mode 100644 index 00000000..72cf0872 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/RuntimeException.java @@ -0,0 +1,102 @@ +/* RuntimeException.java -- root of all unchecked exceptions + Copyright (C) 1998, 1999, 2001, 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +/** + * All exceptions which are subclasses of RuntimeException + * can be thrown at any time during the execution of a Java virtual machine. + * Methods which throw these exceptions are not required to declare them + * in their throws clause. + * + * @author Brian Jones + * @author Warren Levy (warrenl@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @status updated to 1.4 + */ +public class RuntimeException extends Exception +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -7034897190745766939L; + + /** + * Create an exception without a message. The cause remains uninitialized. + * + * @see #initCause(Throwable) + */ + public RuntimeException() + { + } + + /** + * Create an exception with a message. The cause remains uninitialized. + * + * @param s the message string + * @see #initCause(Throwable) + */ + public RuntimeException(String s) + { + super(s); + } + + /** + * Create an exception with a message and a cause. + * + * @param s the message string + * @param cause the cause of this exception + * @since 1.4 + */ + public RuntimeException(String s, Throwable cause) + { + super(s, cause); + } + + /** + * Create an exception with the given cause, and a message of + * cause == null ? null : cause.toString(). + * + * @param cause the cause of this exception + * @since 1.4 + */ + public RuntimeException(Throwable cause) + { + super(cause); + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/SimpleTimeZone.java b/Robust/src/ClassLibrary/MGC/gnu/SimpleTimeZone.java new file mode 100644 index 00000000..f1b7fa2a --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/SimpleTimeZone.java @@ -0,0 +1,1052 @@ +/* java.util.SimpleTimeZone + Copyright (C) 1998, 1999, 2000, 2003, 2004, 2005, 2007 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + + +/** + * This class represents a simple time zone offset and handles + * daylight savings. It can only handle one daylight savings rule, so + * it can't represent historical changes. + * + * This object is tightly bound to the Gregorian calendar. It assumes + * a regular seven days week, and the month lengths are that of the + * Gregorian Calendar. It can only handle daylight savings for years + * lying in the AD era. + * + * @see Calendar + * @see GregorianCalendar + * @author Jochen Hoenicke + */ +public class SimpleTimeZone extends TimeZone +{ + /** + * The raw time zone offset in milliseconds to GMT, ignoring + * daylight savings. + * @serial + */ + private int rawOffset; + + /** + * True, if this timezone uses daylight savings, false otherwise. + * @serial + */ + private boolean useDaylight; + + /** + * The daylight savings offset. This is a positive offset in + * milliseconds with respect to standard time. Typically this + * is one hour, but for some time zones this may be half an hour. + * @serial + * @since JDK1.1.4 + */ + private int dstSavings = 60 * 60 * 1000; + + /** + * The first year, in which daylight savings rules applies. + * @serial + */ + private int startYear; + private static final int DOM_MODE = 1; + private static final int DOW_IN_MONTH_MODE = 2; + private static final int DOW_GE_DOM_MODE = 3; + private static final int DOW_LE_DOM_MODE = 4; + + /** + * The mode of the start rule. This takes one of the following values: + *

+ *
DOM_MODE (1)
+ *
startDay contains the day in month of the start date, + * startDayOfWeek is unused.
+ *
DOW_IN_MONTH_MODE (2)
+ *
The startDay gives the day of week in month, and + * startDayOfWeek the day of week. For example startDay=2 and + * startDayOfWeek=Calender.SUNDAY specifies that the change is on + * the second sunday in that month. You must make sure, that this + * day always exists (ie. don't specify the 5th sunday). + *
+ *
DOW_GE_DOM_MODE (3)
+ *
The start is on the first startDayOfWeek on or after + * startDay. For example startDay=13 and + * startDayOfWeek=Calendar.FRIDAY specifies that the daylight + * savings start on the first FRIDAY on or after the 13th of that + * Month. Make sure that the change is always in the given month, or + * the result is undefined. + *
+ *
DOW_LE_DOM_MONTH (4)
+ *
The start is on the first startDayOfWeek on or before the + * startDay. Make sure that the change is always in the given + * month, or the result is undefined. +
+ *
+ * @serial */ + private int startMode; + + /** + * The month in which daylight savings start. This is one of the + * constants Calendar.JANUARY, ..., Calendar.DECEMBER. + * @serial + */ + private int startMonth; + + /** + * This variable can have different meanings. See startMode for details + * @see #startMode + * @serial + */ + private int startDay; + + /** + * This variable specifies the day of week the change takes place. If + * startMode == DOM_MODE, this is undefined. + * @serial + * @see #startMode + */ + private int startDayOfWeek; + + /** + * This variable specifies the time of change to daylight savings. + * This time is given in milliseconds after midnight in startTimeMode + * chosen time mode. + * @serial + */ + private int startTime; + + /** + * This variable specifies the mode that startTime is specified in. By + * default it is WALL_TIME, but can also be STANDARD_TIME or UTC_TIME. For + * startTime, STANDARD_TIME and WALL_TIME are equivalent. + * @serial + */ + private int startTimeMode = WALL_TIME; + + /** + * The month in which daylight savings ends. This is one of the + * constants Calendar.JANUARY, ..., Calendar.DECEMBER. + * @serial + */ + private int endMonth; + + /** + * This variable gives the mode for the end of daylight savings rule. + * It can take the same values as startMode. + * @serial + * @see #startMode + */ + private int endMode; + + /** + * This variable can have different meanings. See startMode for details + * @serial + * @see #startMode + */ + private int endDay; + + /** + * This variable specifies the day of week the change takes place. If + * endMode == DOM_MODE, this is undefined. + * @serial + * @see #startMode + */ + private int endDayOfWeek; + + /** + * This variable specifies the time of change back to standard time. + * This time is given in milliseconds after midnight in endTimeMode + * chosen time mode. + * @serial + */ + private int endTime; + + /** + * This variable specifies the mode that endTime is specified in. By + * default it is WALL_TIME, but can also be STANDARD_TIME or UTC_TIME. + * @serial + */ + private int endTimeMode = WALL_TIME; + + /** + * This variable points to a deprecated array from JDK 1.1. It is + * ignored in JDK 1.2 but streamed out for compatibility with JDK 1.1. + * The array contains the lengths of the months in the year and is + * assigned from a private static final field to avoid allocating + * the array for every instance of the object. + * Note that static final fields are not serialized. + * @serial + */ + private byte[] monthLength = monthArr; + private static final byte[] monthArr = + { + 31, 28, 31, 30, 31, 30, 31, 31, 30, + 31, 30, 31 + }; + + /** + * The version of the serialized data on the stream. + *
+ *
0 or not present on stream
+ *
JDK 1.1.3 or earlier, only provides this fields: + * rawOffset, startDay, startDayOfWeek, startMonth, startTime, + * startYear, endDay, endDayOfWeek, endMonth, endTime + *
+ *
JDK 1.1.4 or later. This includes three new fields, namely + * startMode, endMode and dstSavings. And there is a optional section + * as described in writeObject. + *
+ *
+ * + * XXX - JDK 1.2 Beta 4 docu states 1.1.4, but my 1.1.5 has the old + * version. + * + * When streaming out this class it is always written in the latest + * version. + * @serial + * @since JDK1.1.4 + */ + private int serialVersionOnStream = 2; + private static final long serialVersionUID = -403250971215465050L; + + /** + * Constant to indicate that start and end times are specified in standard + * time, without adjusting for daylight savings. + */ + public static final int STANDARD_TIME = 1; + + /** + * Constant to indicate that start and end times are specified in wall + * time, adjusting for daylight savings. This is the default. + */ + public static final int WALL_TIME = 0; + + /** + * Constant to indicate that start and end times are specified in UTC. + */ + public static final int UTC_TIME = 2; + + /** + * Create a SimpleTimeZone with the given time offset + * from GMT and without daylight savings. + * @param rawOffset the time offset from GMT in milliseconds. + * @param id The identifier of this time zone. + */ + public SimpleTimeZone(int rawOffset, String id) + { + this.rawOffset = rawOffset; + setID(id); + useDaylight = false; + startYear = 0; + } + + /** + * Create a SimpleTimeZone with the given time offset + * from GMT and with daylight savings. The start/end parameters + * can have different meaning (replace WEEKDAY with a real day of + * week). Only the first two meanings were supported by earlier + * versions of jdk. + * + *
+ *
day > 0, dayOfWeek = Calendar.WEEKDAY
+ *
The start/end of daylight savings is on the day-th + * WEEKDAY in the given month.
+ *
day < 0, dayOfWeek = Calendar.WEEKDAY
+ *
The start/end of daylight savings is on the -day-th + * WEEKDAY counted from the end of the month.
+ *
day > 0, dayOfWeek = 0
+ *
The start/end of daylight is on the day-th day of + * the month.
+ *
day > 0, dayOfWeek = -Calendar.WEEKDAY
+ *
The start/end of daylight is on the first WEEKDAY on or after + * the day-th day of the month. You must make sure that + * this day lies in the same month.
+ *
day < 0, dayOfWeek = -Calendar.WEEKDAY
+ *
The start/end of daylight is on the first WEEKDAY on or + * before the -day-th day of the month. You + * must make sure that this day lies in the same month.
+ *
+ * + * If you give a non existing month, a day that is zero, or too big, + * or a dayOfWeek that is too big, the result is undefined. + * + * The start rule must have a different month than the end rule. + * This restriction shouldn't hurt for all possible time zones. + * + * @param rawOffset The time offset from GMT in milliseconds. + * @param id The identifier of this time zone. + * @param startMonth The start month of daylight savings; use the + * constants in Calendar. + * @param startDayOfWeekInMonth A day in month or a day of week number, as + * described above. + * @param startDayOfWeek The start rule day of week; see above. + * @param startTime A time in millis in standard time. + * @param endMonth The end month of daylight savings; use the + * constants in Calendar. + * @param endDayOfWeekInMonth A day in month or a day of week number, as + * described above. + * @param endDayOfWeek The end rule day of week; see above. + * @param endTime A time in millis in standard time. + * @throws IllegalArgumentException if parameters are invalid or out of + * range. + */ + public SimpleTimeZone(int rawOffset, String id, int startMonth, + int startDayOfWeekInMonth, int startDayOfWeek, + int startTime, int endMonth, int endDayOfWeekInMonth, + int endDayOfWeek, int endTime) + { + this.rawOffset = rawOffset; + setID(id); + useDaylight = true; + + setStartRule(startMonth, startDayOfWeekInMonth, startDayOfWeek, startTime); + setEndRule(endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime); + if (startMonth == endMonth) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "startMonth and endMonth must be different"); + this.startYear = 0; + } + + /** + * This constructs a new SimpleTimeZone that supports a daylight savings + * rule. The parameter are the same as for the constructor above, except + * there is the additional dstSavaings parameter. + * + * @param dstSavings the amount of savings for daylight savings + * time in milliseconds. This must be positive. + * @since 1.2 + */ + public SimpleTimeZone(int rawOffset, String id, int startMonth, + int startDayOfWeekInMonth, int startDayOfWeek, + int startTime, int endMonth, int endDayOfWeekInMonth, + int endDayOfWeek, int endTime, int dstSavings) + { + this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek, + startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime); + + this.dstSavings = dstSavings; + } + + /** + * This constructs a new SimpleTimeZone that supports a daylight savings + * rule. The parameter are the same as for the constructor above, except + * there are the additional startTimeMode, endTimeMode, and dstSavings + * parameters. + * + * @param startTimeMode the mode that start times are specified in. One of + * WALL_TIME, STANDARD_TIME, or UTC_TIME. + * @param endTimeMode the mode that end times are specified in. One of + * WALL_TIME, STANDARD_TIME, or UTC_TIME. + * @param dstSavings the amount of savings for daylight savings + * time in milliseconds. This must be positive. + * @throws IllegalArgumentException if parameters are invalid or out of + * range. + * @since 1.4 + */ + public SimpleTimeZone(int rawOffset, String id, int startMonth, + int startDayOfWeekInMonth, int startDayOfWeek, + int startTime, int startTimeMode, int endMonth, + int endDayOfWeekInMonth, int endDayOfWeek, + int endTime, int endTimeMode, int dstSavings) + { + this(rawOffset, id, startMonth, startDayOfWeekInMonth, startDayOfWeek, + startTime, endMonth, endDayOfWeekInMonth, endDayOfWeek, endTime); + + if (startTimeMode < WALL_TIME || startTimeMode > UTC_TIME) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "startTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME"); + if (endTimeMode < WALL_TIME || endTimeMode > UTC_TIME) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "endTimeMode must be one of WALL_TIME, STANDARD_TIME, or UTC_TIME"); + + this.dstSavings = dstSavings; + this.startTimeMode = startTimeMode; + this.endTimeMode = endTimeMode; + } + + /** + * Sets the first year, where daylight savings applies. The daylight + * savings rule never apply for years in the BC era. Note that this + * is gregorian calendar specific. + * @param year the start year. + */ + public void setStartYear(int year) + { + startYear = year; + useDaylight = true; + } + + /** + * Checks if the month, day, dayOfWeek arguments are in range and + * returns the mode of the rule. + * @param month the month parameter as in the constructor + * @param day the day parameter as in the constructor + * @param dayOfWeek the day of week parameter as in the constructor + * @return the mode of this rule see startMode. + * @exception IllegalArgumentException if parameters are out of range. + * @see #SimpleTimeZone(int, String, int, int, int, int, int, int, int, int) + * @see #startMode + */ + private int checkRule(int month, int day, int dayOfWeek) + { + if (month < 0 || month > 11) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "month out of range"); + + int daysInMonth = getDaysInMonth(month, 1); + if (dayOfWeek == 0) + { + if (day <= 0 || day > daysInMonth) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "day out of range"); + return DOM_MODE; + } + else if (dayOfWeek > 0) + { + if (Math.abs(day) > (daysInMonth + 6) / 7) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "dayOfWeekInMonth out of range"); + if (dayOfWeek > Calendar.SATURDAY) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "dayOfWeek out of range"); + return DOW_IN_MONTH_MODE; + } + else + { + if (day == 0 || Math.abs(day) > daysInMonth) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "day out of range"); + if (dayOfWeek < -Calendar.SATURDAY) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "dayOfWeek out of range"); + if (day < 0) + return DOW_LE_DOM_MODE; + else + return DOW_GE_DOM_MODE; + } + } + + /** + * Sets the daylight savings start rule. You must also set the + * end rule with setEndRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The month where daylight savings start, zero + * based. You should use the constants in Calendar. + * @param day A day of month or day of week in month. + * @param dayOfWeek The day of week where daylight savings start. + * @param time The time in milliseconds standard time where daylight + * savings start. + * @exception IllegalArgumentException if parameters are out of range. + * @see SimpleTimeZone + */ + public void setStartRule(int month, int day, int dayOfWeek, int time) + { + this.startMode = checkRule(month, day, dayOfWeek); + this.startMonth = month; + this.startDay = day; + this.startDayOfWeek = Math.abs(dayOfWeek); + this.startTime = time; + this.startTimeMode = WALL_TIME; + } + + /** + * Sets the daylight savings start rule. You must also set the + * end rule with setEndRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * Note that this API isn't incredibly well specified. It appears that the + * after flag must override the parameters, since normally, the day and + * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or + * before mode is chosen. But if after == true, this implementation + * overrides the signs of the other arguments. And if dayOfWeek == 0, it + * falls back to the behavior in the other APIs. I guess this should be + * checked against Sun's implementation. + * + * @param month The month where daylight savings start, zero + * based. You should use the constants in Calendar. + * @param day A day of month or day of week in month. + * @param dayOfWeek The day of week where daylight savings start. + * @param time The time in milliseconds standard time where daylight + * savings start. + * @param after If true, day and dayOfWeek specify first day of week on or + * after day, else first day of week on or before. + * @since 1.2 + * @see SimpleTimeZone + */ + public void setStartRule(int month, int day, int dayOfWeek, int time, + boolean after) + { + if (after) + setStartRule(month, day, -dayOfWeek, time); + else + setStartRule(month, -day, -dayOfWeek, time); + } + + /** + * Sets the daylight savings start rule. You must also set the + * end rule with setEndRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The month where daylight savings start, zero + * based. You should use the constants in Calendar. + * @param day A day of month or day of week in month. + * @param time The time in milliseconds standard time where daylight + * savings start. + * @see SimpleTimeZone + * @since 1.2 + */ + public void setStartRule(int month, int day, int time) + { + setStartRule(month, day, 0, time); + } + + /** + * Sets the daylight savings end rule. You must also set the + * start rule with setStartRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The end month of daylight savings. + * @param day A day in month, or a day of week in month. + * @param dayOfWeek A day of week, when daylight savings ends. + * @param time A time in millis in standard time. + * @see #setStartRule(int, int, int, int) + */ + public void setEndRule(int month, int day, int dayOfWeek, int time) + { + this.endMode = checkRule(month, day, dayOfWeek); + this.endMonth = month; + this.endDay = day; + this.endDayOfWeek = Math.abs(dayOfWeek); + this.endTime = time; + this.endTimeMode = WALL_TIME; + useDaylight = true; + } + + /** + * Sets the daylight savings end rule. You must also set the + * start rule with setStartRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * Note that this API isn't incredibly well specified. It appears that the + * after flag must override the parameters, since normally, the day and + * dayofweek can select this. I.e., if day < 0 and dayOfWeek < 0, on or + * before mode is chosen. But if after == true, this implementation + * overrides the signs of the other arguments. And if dayOfWeek == 0, it + * falls back to the behavior in the other APIs. I guess this should be + * checked against Sun's implementation. + * + * @param month The end month of daylight savings. + * @param day A day in month, or a day of week in month. + * @param dayOfWeek A day of week, when daylight savings ends. + * @param time A time in millis in standard time. + * @param after If true, day and dayOfWeek specify first day of week on or + * after day, else first day of week on or before. + * @since 1.2 + * @see #setStartRule(int, int, int, int, boolean) + */ + public void setEndRule(int month, int day, int dayOfWeek, int time, + boolean after) + { + if (after) + setEndRule(month, day, -dayOfWeek, time); + else + setEndRule(month, -day, -dayOfWeek, time); + } + + /** + * Sets the daylight savings end rule. You must also set the + * start rule with setStartRule or the result of + * getOffset is undefined. For the parameters see the ten-argument + * constructor above. + * + * @param month The end month of daylight savings. + * @param day A day in month, or a day of week in month. + * @param time A time in millis in standard time. + * @see #setStartRule(int, int, int) + */ + public void setEndRule(int month, int day, int time) + { + setEndRule(month, day, 0, time); + } + + /** + * Gets the time zone offset, for current date, modified in case of + * daylight savings. This is the offset to add to UTC to get the local + * time. + * + * In the standard JDK the results given by this method may result in + * inaccurate results at the end of February or the beginning of March. + * To avoid this, you should use Calendar instead: + * offset = cal.get(Calendar.ZONE_OFFSET) + * + cal.get(Calendar.DST_OFFSET); + * + * This version doesn't suffer this inaccuracy. + * + * The arguments don't follow the approach for setting start and end rules. + * The day must be a positive number and dayOfWeek must be a positive value + * from Calendar. dayOfWeek is redundant, but must match the other values + * or an inaccurate result may be returned. + * + * @param era the era of the given date + * @param year the year of the given date + * @param month the month of the given date, 0 for January. + * @param day the day of month + * @param dayOfWeek the day of week; this must match the other fields. + * @param millis the millis in the day (in local standard time) + * @return the time zone offset in milliseconds. + * @throws IllegalArgumentException if arguments are incorrect. + */ + public int getOffset(int era, int year, int month, int day, int dayOfWeek, + int millis) + { + int daysInMonth = getDaysInMonth(month, year); + if (day < 1 || day > daysInMonth) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "day out of range"); + if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "dayOfWeek out of range"); + if (month < Calendar.JANUARY || month > Calendar.DECEMBER) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "month out of range:" + month); + + // This method is called by Calendar, so we mustn't use that class. + int daylightSavings = 0; + if (useDaylight && era == GregorianCalendar.AD && year >= startYear) + { + int orig_year = year; + int time = startTime + (startTimeMode == UTC_TIME ? rawOffset : 0); + // This does only work for Gregorian calendars :-( + // This is mainly because setStartYear doesn't take an era. + boolean afterStart = ! isBefore(year, month, day, dayOfWeek, millis, + startMode, startMonth, startDay, + startDayOfWeek, time); + millis += dstSavings; + if (millis >= 24 * 60 * 60 * 1000) + { + millis -= 24 * 60 * 60 * 1000; + dayOfWeek = (dayOfWeek % 7) + 1; + if (++day > daysInMonth) + { + day = 1; + if (month++ == Calendar.DECEMBER) + { + month = Calendar.JANUARY; + year++; + } + } + } + time = endTime + (endTimeMode == UTC_TIME ? rawOffset : 0); + if (endTimeMode != WALL_TIME) + time += dstSavings; + boolean beforeEnd = isBefore(year, month, day, dayOfWeek, millis, + endMode, endMonth, endDay, endDayOfWeek, + time); + + if (year != orig_year) + afterStart = false; + if (startMonth < endMonth) + // use daylight savings, if the date is after the start of + // savings, and before the end of savings. + daylightSavings = afterStart && beforeEnd ? dstSavings : 0; + else + // use daylight savings, if the date is before the end of + // savings, or after the start of savings. + daylightSavings = beforeEnd || afterStart ? dstSavings : 0; + } + return rawOffset + daylightSavings; + } + + /** + * Returns the time zone offset to GMT in milliseconds, ignoring + * day light savings. + * @return the time zone offset. + */ + public int getRawOffset() + { + return rawOffset; + } + + /** + * Sets the standard time zone offset to GMT. + * @param rawOffset The time offset from GMT in milliseconds. + */ + public void setRawOffset(int rawOffset) + { + this.rawOffset = rawOffset; + } + + /** + * Gets the daylight savings offset. This is a positive offset in + * milliseconds with respect to standard time. Typically this + * is one hour, but for some time zones this may be half an our. + * @return the daylight savings offset in milliseconds. + * + * @since 1.2 + */ + public int getDSTSavings() + { + return dstSavings; + } + + /** + * Sets the daylight savings offset. This is a positive offset in + * milliseconds with respect to standard time. + * + * @param dstSavings the daylight savings offset in milliseconds. + * + * @since 1.2 + */ + public void setDSTSavings(int dstSavings) + { + if (dstSavings <= 0) + throw new Exception/*IllegalArgumentException*/("IllegalArgumentException: " + "illegal value for dstSavings"); + + this.dstSavings = dstSavings; + } + + /** + * Returns if this time zone uses daylight savings time. + * @return true, if we use daylight savings time, false otherwise. + */ + public boolean useDaylightTime() + { + return useDaylight; + } + + /** + * Returns the number of days in the given month. + * Uses gregorian rules prior to 1582 (The default and earliest cutover) + * @param month The month, zero based; use one of the Calendar constants. + * @param year The year. + */ + private int getDaysInMonth(int month, int year) + { + if (month == Calendar.FEBRUARY) + { + if ((year & 3) != 0) + return 28; + + // Assume default Gregorian cutover, + // all years prior to this must be Julian + if (year < 1582) + return 29; + + // Gregorian rules + return ((year % 100) != 0 || (year % 400) == 0) ? 29 : 28; + } + else + return monthArr[month]; + } + + /** + * Checks if the date given in calXXXX, is before the change between + * dst and standard time. + * @param calYear the year of the date to check (for leap day checking). + * @param calMonth the month of the date to check. + * @param calDayOfMonth the day of month of the date to check. + * @param calDayOfWeek the day of week of the date to check. + * @param calMillis the millis of day of the date to check (standard time). + * @param mode the change mode; same semantic as startMode. + * @param month the change month; same semantic as startMonth. + * @param day the change day; same semantic as startDay. + * @param dayOfWeek the change day of week; + * @param millis the change time in millis since midnight standard time. + * same semantic as startDayOfWeek. + * @return true, if cal is before the change, false if cal is on + * or after the change. + */ + private boolean isBefore(int calYear, int calMonth, int calDayOfMonth, + int calDayOfWeek, int calMillis, int mode, + int month, int day, int dayOfWeek, int millis) + { + // This method is called by Calendar, so we mustn't use that class. + // We have to do all calculations by hand. + // check the months: + // XXX - this is not correct: + // for the DOW_GE_DOM and DOW_LE_DOM modes the change date may + // be in a different month. + if (calMonth != month) + return calMonth < month; + + // check the day: + switch (mode) + { + case DOM_MODE: + if (calDayOfMonth != day) + return calDayOfMonth < day; + break; + case DOW_IN_MONTH_MODE: + { + // This computes the day of month of the day of type + // "dayOfWeek" that lies in the same (sunday based) week as cal. + calDayOfMonth += (dayOfWeek - calDayOfWeek); + + // Now we convert it to 7 based number (to get a one based offset + // after dividing by 7). If we count from the end of the + // month, we get want a -7 based number counting the days from + // the end: + if (day < 0) + calDayOfMonth -= getDaysInMonth(calMonth, calYear) + 7; + else + calDayOfMonth += 6; + + // day > 0 day < 0 + // S M T W T F S S M T W T F S + // 7 8 9 10 11 12 -36-35-34-33-32-31 + // 13 14 15 16 17 18 19 -30-29-28-27-26-25-24 + // 20 21 22 23 24 25 26 -23-22-21-20-19-18-17 + // 27 28 29 30 31 32 33 -16-15-14-13-12-11-10 + // 34 35 36 -9 -8 -7 + // Now we calculate the day of week in month: + int week = calDayOfMonth / 7; + + // day > 0 day < 0 + // S M T W T F S S M T W T F S + // 1 1 1 1 1 1 -5 -5 -4 -4 -4 -4 + // 1 2 2 2 2 2 2 -4 -4 -4 -3 -3 -3 -3 + // 2 3 3 3 3 3 3 -3 -3 -3 -2 -2 -2 -2 + // 3 4 4 4 4 4 4 -2 -2 -2 -1 -1 -1 -1 + // 4 5 5 -1 -1 -1 + if (week != day) + return week < day; + + if (calDayOfWeek != dayOfWeek) + return calDayOfWeek < dayOfWeek; + + // daylight savings starts/ends on the given day. + break; + } + case DOW_LE_DOM_MODE: + // The greatest sunday before or equal December, 12 + // is the same as smallest sunday after or equal December, 6. + day = Math.abs(day) - 6; + case DOW_GE_DOM_MODE: + // Calculate the day of month of the day of type + // "dayOfWeek" that lies before (or on) the given date. + calDayOfMonth -= (calDayOfWeek < dayOfWeek ? 7 : 0) + calDayOfWeek + - dayOfWeek; + if (calDayOfMonth < day) + return true; + if (calDayOfWeek != dayOfWeek || calDayOfMonth >= day + 7) + return false; + + // now we have the same day + break; + } + + // the millis decides: + return (calMillis < millis); + } + + /** + * Determines if the given date is in daylight savings time. + * @return true, if it is in daylight savings time, false otherwise. + */ + public boolean inDaylightTime(Date date) + { + Calendar cal = Calendar.getInstance(this); + cal.setTime(date); + return (cal.get(Calendar.DST_OFFSET) != 0); + } + + /** + * Generates the hashCode for the SimpleDateFormat object. It is + * the rawOffset, possibly, if useDaylightSavings is true, xored + * with startYear, startMonth, startDayOfWeekInMonth, ..., endTime. + */ + public synchronized int hashCode() + { + return rawOffset + ^ (useDaylight + ? startMonth ^ startDay ^ startDayOfWeek ^ startTime ^ endMonth + ^ endDay ^ endDayOfWeek ^ endTime : 0); + } + + public synchronized boolean equals(Object o) + { + if (this == o) + return true; + if (! (o instanceof SimpleTimeZone)) + return false; + SimpleTimeZone zone = (SimpleTimeZone) o; + if (zone.hashCode() != hashCode() || ! getID().equals(zone.getID()) + || rawOffset != zone.rawOffset || useDaylight != zone.useDaylight) + return false; + if (! useDaylight) + return true; + return (startYear == zone.startYear && startMonth == zone.startMonth + && startDay == zone.startDay + && startDayOfWeek == zone.startDayOfWeek + && startTime == zone.startTime + && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth + && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek + && endTime == zone.endTime && endTimeMode == zone.endTimeMode); + } + + /** + * Test if the other time zone uses the same rule and only + * possibly differs in ID. This implementation for this particular + * class will return true if the other object is a SimpleTimeZone, + * the raw offsets and useDaylight are identical and if useDaylight + * is true, also the start and end datas are identical. + * @return true if this zone uses the same rule. + */ + public boolean hasSameRules(TimeZone other) + { + if (this == other) + return true; + if (! (other instanceof SimpleTimeZone)) + return false; + SimpleTimeZone zone = (SimpleTimeZone) other; + if (zone.hashCode() != hashCode() || rawOffset != zone.rawOffset + || useDaylight != zone.useDaylight) + return false; + if (! useDaylight) + return true; + return (startYear == zone.startYear && startMonth == zone.startMonth + && startDay == zone.startDay + && startDayOfWeek == zone.startDayOfWeek + && startTime == zone.startTime + && startTimeMode == zone.startTimeMode && endMonth == zone.endMonth + && endDay == zone.endDay && endDayOfWeek == zone.endDayOfWeek + && endTime == zone.endTime && endTimeMode == zone.endTimeMode); + } + + /** + * Returns a string representation of this SimpleTimeZone object. + * @return a string representation of this SimpleTimeZone object. + */ + public String toString() + { + // the test for useDaylight is an incompatibility to jdk1.2, but + // I think this shouldn't hurt. + return "SimpleTimeZone"/*getClass().getName()*/ + "[" + "id=" + getID() + ",offset=" + + rawOffset + ",dstSavings=" + dstSavings + ",useDaylight=" + + useDaylight + + (useDaylight + ? ",startYear=" + startYear + ",startMode=" + startMode + + ",startMonth=" + startMonth + ",startDay=" + startDay + + ",startDayOfWeek=" + startDayOfWeek + ",startTime=" + + startTime + ",startTimeMode=" + startTimeMode + ",endMode=" + + endMode + ",endMonth=" + endMonth + ",endDay=" + endDay + + ",endDayOfWeek=" + endDayOfWeek + ",endTime=" + endTime + + ",endTimeMode=" + endTimeMode : "") + "]"; + } + + /** + * Reads a serialized simple time zone from stream. + * @see #writeObject + */ + private void readObject(java.io.ObjectInputStream input) + //throws java.io.IOException, ClassNotFoundException + { + input.defaultReadObject(); + if (serialVersionOnStream == 0) + { + // initialize the new fields to default values. + dstSavings = 60 * 60 * 1000; + endMode = DOW_IN_MONTH_MODE; + startMode = DOW_IN_MONTH_MODE; + startTimeMode = WALL_TIME; + endTimeMode = WALL_TIME; + serialVersionOnStream = 2; + } + else + { + int length = input.readInt(); + byte[] byteArray = new byte[length]; + input.read(byteArray, 0, length); + if (length >= 4) + { + // Lets hope that Sun does extensions to the serialized + // form in a sane manner. + startDay = byteArray[0]; + startDayOfWeek = byteArray[1]; + endDay = byteArray[2]; + endDayOfWeek = byteArray[3]; + } + } + } + + /** + * Serializes this object to a stream. @serialdata The object is + * first written in the old JDK 1.1 format, so that it can be read + * by the old classes. This means, that the + * start/endDay(OfWeek)-Fields are written in the + * DOW_IN_MONTH_MODE rule, since this was the only supported rule + * in 1.1. + * + * In the optional section, we write first the length of an byte + * array as int and afterwards the byte array itself. The byte + * array contains in this release four elements, namely the real + * startDay, startDayOfWeek endDay, endDayOfWeek in that Order. + * These fields are needed, because for compatibility reasons only + * approximative values are written to the required section, as + * described above. + */ + private void writeObject(java.io.ObjectOutputStream output) + //throws java.io.IOException + { + byte[] byteArray = new byte[] + { + (byte) startDay, (byte) startDayOfWeek, (byte) endDay, + (byte) endDayOfWeek + }; + + /* calculate the approximation for JDK 1.1 */ + switch (startMode) + { + case DOM_MODE: + startDayOfWeek = Calendar.SUNDAY; // random day of week + + // fall through + case DOW_GE_DOM_MODE: + case DOW_LE_DOM_MODE: + startDay = (startDay + 6) / 7; + } + switch (endMode) + { + case DOM_MODE: + endDayOfWeek = Calendar.SUNDAY; + + // fall through + case DOW_GE_DOM_MODE: + case DOW_LE_DOM_MODE: + endDay = (endDay + 6) / 7; + } + + // the required part: + output.defaultWriteObject(); + // the optional part: + output.writeInt(byteArray.length); + output.write(byteArray, 0, byteArray.length); + } +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/Throwable.java b/Robust/src/ClassLibrary/MGC/gnu/Throwable.java new file mode 100644 index 00000000..3efa9d49 --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/Throwable.java @@ -0,0 +1,565 @@ +/* java.lang.Throwable -- Root class for all Exceptions and Errors + Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +/*import gnu.classpath.SystemProperties; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.Serializable;*/ + +/** + * Throwable is the superclass of all exceptions that can be raised. + * + *

There are two special cases: {@link Error} and {@link RuntimeException}: + * these two classes (and their subclasses) are considered unchecked + * exceptions, and are either frequent enough or catastrophic enough that you + * do not need to declare them in throws clauses. Everything + * else is a checked exception, and is ususally a subclass of + * {@link Exception}; these exceptions have to be handled or declared. + * + *

Instances of this class are usually created with knowledge of the + * execution context, so that you can get a stack trace of the problem spot + * in the code. Also, since JDK 1.4, Throwables participate in "exception + * chaining." This means that one exception can be caused by another, and + * preserve the information of the original. + * + *

One reason this is useful is to wrap exceptions to conform to an + * interface. For example, it would be bad design to require all levels + * of a program interface to be aware of the low-level exceptions thrown + * at one level of abstraction. Another example is wrapping a checked + * exception in an unchecked one, to communicate that failure occured + * while still obeying the method throws clause of a superclass. + * + *

A cause is assigned in one of two ways; but can only be assigned once + * in the lifetime of the Throwable. There are new constructors added to + * several classes in the exception hierarchy that directly initialize the + * cause, or you can use the initCause method. This second + * method is especially useful if the superclass has not been retrofitted + * with new constructors:
+ *

+ * try
+ *   {
+ *     lowLevelOp();
+ *   }
+ * catch (LowLevelException lle)
+ *   {
+ *     throw (HighLevelException) new HighLevelException().initCause(lle);
+ *   }
+ * 
+ * Notice the cast in the above example; without it, your method would need + * a throws clase that declared Throwable, defeating the purpose of chainig + * your exceptions. + * + *

By convention, exception classes have two constructors: one with no + * arguments, and one that takes a String for a detail message. Further, + * classes which are likely to be used in an exception chain also provide + * a constructor that takes a Throwable, with or without a detail message + * string. + * + *

Another 1.4 feature is the StackTrace, a means of reflection that + * allows the program to inspect the context of the exception, and which is + * serialized, so that remote procedure calls can correctly pass exceptions. + * + * @author Brian Jones + * @author John Keiser + * @author Mark Wielaard + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public class Throwable //implements Serializable +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = -3042686055658047285L; + + /** + * The detail message. + * + * @serial specific details about the exception, may be null + */ + private final String detailMessage; + + /** + * The cause of the throwable, including null for an unknown or non-chained + * cause. This may only be set once; so the field is set to + * this until initialized. + * + * @serial the cause, or null if unknown, or this if not yet set + * @since 1.4 + */ + private Throwable cause = this; + + /** + * The stack trace, in a serialized form. + * + * @serial the elements of the stack trace; this is non-null, and has + * no null entries + * @since 1.4 + */ + //private StackTraceElement[] stackTrace; + + /** + * Instantiate this Throwable with an empty message. The cause remains + * uninitialized. {@link #fillInStackTrace()} will be called to set + * up the stack trace. + */ + public Throwable() + { + this((String) null); + } + + /** + * Instantiate this Throwable with the given message. The cause remains + * uninitialized. {@link #fillInStackTrace()} will be called to set + * up the stack trace. + * + * @param message the message to associate with the Throwable + */ + public Throwable(String message) + { + //fillInStackTrace(); + detailMessage = message; + } + + /** + * Instantiate this Throwable with the given message and cause. Note that + * the message is unrelated to the message of the cause. + * {@link #fillInStackTrace()} will be called to set up the stack trace. + * + * @param message the message to associate with the Throwable + * @param cause the cause, may be null + * @since 1.4 + */ + public Throwable(String message, Throwable cause) + { + this(message); + this.cause = cause; + } + + /** + * Instantiate this Throwable with the given cause. The message is then + * built as cause == null ? null : cause.toString(). + * {@link #fillInStackTrace()} will be called to set up the stack trace. + * + * @param cause the cause, may be null + * @since 1.4 + */ + public Throwable(Throwable cause) + { + this(cause == null ? null : cause.toString(), cause); + } + + /** + * Get the message associated with this Throwable. + * + * @return the error message associated with this Throwable, may be null + */ + public String getMessage() + { + return detailMessage; + } + + /** + * Get a localized version of this Throwable's error message. + * This method must be overridden in a subclass of Throwable + * to actually produce locale-specific methods. The Throwable + * implementation just returns getMessage(). + * + * @return a localized version of this error message + * @see #getMessage() + * @since 1.1 + */ + public String getLocalizedMessage() + { + return getMessage(); + } + + /** + * Returns the cause of this exception, or null if the cause is not known + * or non-existant. This cause is initialized by the new constructors, + * or by calling initCause. + * + * @return the cause of this Throwable + * @since 1.4 + */ + public Throwable getCause() + { + return cause == this ? null : cause; + } + + /** + * Initialize the cause of this Throwable. This may only be called once + * during the object lifetime, including implicitly by chaining + * constructors. + * + * @param cause the cause of this Throwable, may be null + * @return this + * @throws IllegalArgumentException if cause is this (a Throwable can't be + * its own cause!) + * @throws IllegalStateException if the cause has already been set + * @since 1.4 + */ + public Throwable initCause(Throwable cause) + { + /*if (cause == this) + throw new IllegalArgumentException(); + if (this.cause != this) + throw new IllegalStateException();*/ + this.cause = cause; + return this; + } + + /** + * Get a human-readable representation of this Throwable. The detail message + * is retrieved by getLocalizedMessage(). Then, with a null detail + * message, this string is simply the object's class name; otherwise + * the string is getClass().getName() + ": " + message. + * + * @return a human-readable String represting this Throwable + */ + /*public String toString() + { + String msg = getLocalizedMessage(); + return getClass().getName() + (msg == null ? "" : ": " + msg); + }*/ + + /** + * Print a stack trace to the standard error stream. This stream is the + * current contents of System.err. The first line of output + * is the result of {@link #toString()}, and the remaining lines represent + * the data created by {@link #fillInStackTrace()}. While the format is + * unspecified, this implementation uses the suggested format, demonstrated + * by this example:
+ *

+   * public class Junk
+   * {
+   *   public static void main(String args[])
+   *   {
+   *     try
+   *       {
+   *         a();
+   *       }
+   *     catch(HighLevelException e)
+   *       {
+   *         e.printStackTrace();
+   *       }
+   *   }
+   *   static void a() throws HighLevelException
+   *   {
+   *     try
+   *       {
+   *         b();
+   *       }
+   *     catch(MidLevelException e)
+   *       {
+   *         throw new HighLevelException(e);
+   *       }
+   *   }
+   *   static void b() throws MidLevelException
+   *   {
+   *     c();
+   *   }
+   *   static void c() throws MidLevelException
+   *   {
+   *     try
+   *       {
+   *         d();
+   *       }
+   *     catch(LowLevelException e)
+   *       {
+   *         throw new MidLevelException(e);
+   *       }
+   *   }
+   *   static void d() throws LowLevelException
+   *   {
+   *     e();
+   *   }
+   *   static void e() throws LowLevelException
+   *   {
+   *     throw new LowLevelException();
+   *   }
+   * }
+   * class HighLevelException extends Exception
+   * {
+   *   HighLevelException(Throwable cause) { super(cause); }
+   * }
+   * class MidLevelException extends Exception
+   * {
+   *   MidLevelException(Throwable cause)  { super(cause); }
+   * }
+   * class LowLevelException extends Exception
+   * {
+   * }
+   * 
+ *

+ *

+   *  HighLevelException: MidLevelException: LowLevelException
+   *          at Junk.a(Junk.java:13)
+   *          at Junk.main(Junk.java:4)
+   *  Caused by: MidLevelException: LowLevelException
+   *          at Junk.c(Junk.java:23)
+   *          at Junk.b(Junk.java:17)
+   *          at Junk.a(Junk.java:11)
+   *          ... 1 more
+   *  Caused by: LowLevelException
+   *          at Junk.e(Junk.java:30)
+   *          at Junk.d(Junk.java:27)
+   *          at Junk.c(Junk.java:21)
+   *          ... 3 more
+   * 
+ */ + public void printStackTrace() + { + //printStackTrace(System.err); + } + + /** + * Print a stack trace to the specified PrintStream. See + * {@link #printStackTrace()} for the sample format. + * + * @param s the PrintStream to write the trace to + */ + /*public void printStackTrace(PrintStream s) + { + s.print(stackTraceString()); + }*/ + + /** + * Prints the exception, the detailed message and the stack trace + * associated with this Throwable to the given PrintWriter. + * The actual output written is implemention specific. Use the result of + * getStackTrace() when more precise information is needed. + * + *

This implementation first prints a line with the result of this + * object's toString() method. + *
+ * Then for all elements given by getStackTrace it prints + * a line containing three spaces, the string "at " and the result of calling + * the toString() method on the StackTraceElement + * object. If getStackTrace() returns an empty array it prints + * a line containing three spaces and the string + * "<<No stacktrace available>>". + *
+ * Then if getCause() doesn't return null it adds a line + * starting with "Caused by: " and the result of calling + * toString() on the cause. + *
+ * Then for every cause (of a cause, etc) the stacktrace is printed the + * same as for the top level Throwable except that as soon + * as all the remaining stack frames of the cause are the same as the + * the last stack frames of the throwable that the cause is wrapped in + * then a line starting with three spaces and the string "... X more" is + * printed, where X is the number of remaining stackframes. + * + * @param pw the PrintWriter to write the trace to + * @since 1.1 + */ + /*public void printStackTrace (PrintWriter pw) + { + pw.print(stackTraceString()); + }*/ + + /* + * We use inner class to avoid a static initializer in this basic class. + */ + /*private static class StaticData + { + static final String nl = SystemProperties.getProperty("line.separator"); + }*/ + + // Create whole stack trace in a stringbuffer so we don't have to print + // it line by line. This prevents printing multiple stack traces from + // different threads to get mixed up when written to the same PrintWriter. + /*private String stackTraceString() + { + CPStringBuilder sb = new CPStringBuilder(); + + // Main stacktrace + StackTraceElement[] stack = getStackTrace(); + stackTraceStringBuffer(sb, this.toString(), stack, 0); + + // The cause(s) + Throwable cause = getCause(); + while (cause != null) + { + // Cause start first line + sb.append("Caused by: "); + + // Cause stacktrace + StackTraceElement[] parentStack = stack; + stack = cause.getStackTrace(); + if (parentStack == null || parentStack.length == 0) + stackTraceStringBuffer(sb, cause.toString(), stack, 0); + else + { + int equal = 0; // Count how many of the last stack frames are equal + int frame = stack.length-1; + int parentFrame = parentStack.length-1; + while (frame > 0 && parentFrame > 0) + { + if (stack[frame].equals(parentStack[parentFrame])) + { + equal++; + frame--; + parentFrame--; + } + else + break; + } + stackTraceStringBuffer(sb, cause.toString(), stack, equal); + } + cause = cause.getCause(); + } + + return sb.toString(); + }*/ + + // Adds to the given StringBuffer a line containing the name and + // all stacktrace elements minus the last equal ones. + /*private static void stackTraceStringBuffer(CPStringBuilder sb, String name, + StackTraceElement[] stack, int equal) + { + String nl = StaticData.nl; + // (finish) first line + sb.append(name); + sb.append(nl); + + // The stacktrace + if (stack == null || stack.length == 0) + { + sb.append(" <>"); + sb.append(nl); + } + else + { + for (int i = 0; i < stack.length-equal; i++) + { + sb.append(" at "); + sb.append(stack[i] == null ? "<>" : stack[i].toString()); + sb.append(nl); + } + if (equal > 0) + { + sb.append(" ..."); + sb.append(equal); + sb.append(" more"); + sb.append(nl); + } + } + }*/ + + /** + * Fill in the stack trace with the current execution stack. + * + * @return this same throwable + * @see #printStackTrace() + */ + /*public Throwable fillInStackTrace() + { + vmState = VMThrowable.fillInStackTrace(this); + stackTrace = null; // Should be regenerated when used. + + return this; + }*/ + + /** + * Provides access to the information printed in {@link #printStackTrace()}. + * The array is non-null, with no null entries, although the virtual + * machine is allowed to skip stack frames. If the array is not 0-length, + * then slot 0 holds the information on the stack frame where the Throwable + * was created (or at least where fillInStackTrace() was + * called). + * + * @return an array of stack trace information, as available from the VM + * @since 1.4 + */ + /*public StackTraceElement[] getStackTrace() + { + if (stackTrace == null) + if (vmState == null) + stackTrace = new StackTraceElement[0]; + else + { + stackTrace = vmState.getStackTrace(this); + vmState = null; // No longer needed + } + + return stackTrace; + }*/ + + /** + * Change the stack trace manually. This method is designed for remote + * procedure calls, which intend to alter the stack trace before or after + * serialization according to the context of the remote call. + *

+ * The contents of the given stacktrace is copied so changes to the + * original array do not change the stack trace elements of this + * throwable. + * + * @param stackTrace the new trace to use + * @throws NullPointerException if stackTrace is null or has null elements + * @since 1.4 + */ + /*public void setStackTrace(StackTraceElement[] stackTrace) + { + int i = stackTrace.length; + StackTraceElement[] st = new StackTraceElement[i]; + + while (--i >= 0) + { + st[i] = stackTrace[i]; + if (st[i] == null) + throw new NullPointerException("Element " + i + " null"); + } + + this.stackTrace = st; + }*/ + + /** + * VM state when fillInStackTrace was called. + * Used by getStackTrace() to get an array of StackTraceElements. + * Cleared when no longer needed. + */ + //private transient VMThrowable vmState; +} diff --git a/Robust/src/ClassLibrary/MGC/gnu/TimeZone.java b/Robust/src/ClassLibrary/MGC/gnu/TimeZone.java new file mode 100644 index 00000000..db5dd13f --- /dev/null +++ b/Robust/src/ClassLibrary/MGC/gnu/TimeZone.java @@ -0,0 +1,1777 @@ +/* java.util.TimeZone + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +/*import gnu.classpath.SystemProperties; +import gnu.java.lang.CPStringBuilder; +import gnu.java.util.ZoneInfo; + +import java.io.File; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.text.DateFormatSymbols;*/ + +/** + * This class represents a time zone offset and handles daylight savings. + * + * You can get the default time zone with getDefault. + * This represents the time zone where program is running. + * + * Another way to create a time zone is getTimeZone, where + * you can give an identifier as parameter. For instance, the identifier + * of the Central European Time zone is "CET". + * + * With the getAvailableIDs method, you can get all the + * supported time zone identifiers. + * + * @see Calendar + * @see SimpleTimeZone + * @author Jochen Hoenicke + */ +public abstract class TimeZone //implements java.io.Serializable, Cloneable +{ + + /** + * Constant used to indicate that a short timezone abbreviation should + * be returned, such as "EST" + */ + public static final int SHORT = 0; + + /** + * Constant used to indicate that a long timezone name should be + * returned, such as "Eastern Standard Time". + */ + public static final int LONG = 1; + + /** + * The time zone identifier, e.g. PST. + */ + private String ID; + + /** + * The default time zone, as returned by getDefault. + */ + private static TimeZone defaultZone0; + + /** + * Tries to get the default TimeZone for this system if not already + * set. It will call getDefaultTimeZone(String) with + * the result of System.getProperty("user.timezone"). + * If that fails it calls VMTimeZone.getDefaultTimeZoneId(). + * If that also fails GMT is returned. + */ + private static synchronized TimeZone defaultZone() + { + /* Look up default timezone */ + if (defaultZone0 == null) + { + /*defaultZone0 = (TimeZone) AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + TimeZone zone = null; + + // Prefer System property user.timezone. + String tzid = System.getProperty("user.timezone"); + if (tzid != null && !tzid.equals("")) + zone = getDefaultTimeZone(tzid); + + // Try platfom specific way. + if (zone == null) + zone = VMTimeZone.getDefaultTimeZoneId(); + + // Fall back on GMT. + if (zone == null) + zone = getTimeZone ("GMT"); + + return zone; + } + });*/ + } + + return defaultZone0; + } + + private static final long serialVersionUID = 3581463369166924961L; + + /** + * Flag whether zoneinfo data should be used, + * otherwise builtin timezone data will be provided. + */ + private static String zoneinfo_dir; + + /** + * Cached copy of getAvailableIDs(). + */ + private static String[] availableIDs = null; + + /** + * JDK 1.1.x compatibility aliases. + */ + private static HashMap aliases0; + + /** + * HashMap for timezones by ID. + */ + private static HashMap timezones0; + /* initialize this static field lazily to overhead if + * it is not needed: + */ + // Package-private to avoid a trampoline. + static HashMap timezones() + { + if (timezones0 == null) + { + HashMap timezones = new HashMap(); + timezones0 = timezones; + + /*zoneinfo_dir = SystemProperties.getProperty("gnu.java.util.zoneinfo.dir"); + if (zoneinfo_dir != null && !new File(zoneinfo_dir).isDirectory()) + zoneinfo_dir = null;*/ + + if (zoneinfo_dir != null) + { + aliases0 = new HashMap(); + + // These deprecated aliases for JDK 1.1.x compatibility + // should take precedence over data files read from + // /usr/share/zoneinfo. + aliases0.put("ACT", "Australia/Darwin"); + aliases0.put("AET", "Australia/Sydney"); + aliases0.put("AGT", "America/Argentina/Buenos_Aires"); + aliases0.put("ART", "Africa/Cairo"); + aliases0.put("AST", "America/Juneau"); + aliases0.put("BST", "Asia/Colombo"); + aliases0.put("CAT", "Africa/Gaborone"); + aliases0.put("CNT", "America/St_Johns"); + aliases0.put("CST", "CST6CDT"); + aliases0.put("CTT", "Asia/Brunei"); + aliases0.put("EAT", "Indian/Comoro"); + aliases0.put("ECT", "CET"); + aliases0.put("EST", "EST5EDT"); + aliases0.put("EST5", "EST5EDT"); + aliases0.put("IET", "EST5EDT"); + aliases0.put("IST", "Asia/Calcutta"); + aliases0.put("JST", "Asia/Seoul"); + aliases0.put("MIT", "Pacific/Niue"); + aliases0.put("MST", "MST7MDT"); + aliases0.put("MST7", "MST7MDT"); + aliases0.put("NET", "Indian/Mauritius"); + aliases0.put("NST", "Pacific/Auckland"); + aliases0.put("PLT", "Indian/Kerguelen"); + aliases0.put("PNT", "MST7MDT"); + aliases0.put("PRT", "America/Anguilla"); + aliases0.put("PST", "PST8PDT"); + aliases0.put("SST", "Pacific/Ponape"); + aliases0.put("VST", "Asia/Bangkok"); + return timezones; + } + + TimeZone tz; + // Automatically generated by scripts/timezones.pl + // XXX - Should we read this data from a file? + tz = new SimpleTimeZone(-11000 * 3600, "MIT"); + timezones0.put("MIT", tz); + timezones0.put("Pacific/Apia", tz); + timezones0.put("Pacific/Midway", tz); + timezones0.put("Pacific/Niue", tz); + timezones0.put("Pacific/Pago_Pago", tz); + tz = new SimpleTimeZone + (-10000 * 3600, "America/Adak", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Adak", tz); + tz = new SimpleTimeZone(-10000 * 3600, "HST"); + timezones0.put("HST", tz); + timezones0.put("Pacific/Fakaofo", tz); + timezones0.put("Pacific/Honolulu", tz); + timezones0.put("Pacific/Johnston", tz); + timezones0.put("Pacific/Rarotonga", tz); + timezones0.put("Pacific/Tahiti", tz); + tz = new SimpleTimeZone(-9500 * 3600, "Pacific/Marquesas"); + timezones0.put("Pacific/Marquesas", tz); + tz = new SimpleTimeZone + (-9000 * 3600, "AST", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("AST", tz); + timezones0.put("America/Anchorage", tz); + timezones0.put("America/Juneau", tz); + timezones0.put("America/Nome", tz); + timezones0.put("America/Yakutat", tz); + tz = new SimpleTimeZone(-9000 * 3600, "Pacific/Gambier"); + timezones0.put("Pacific/Gambier", tz); + tz = new SimpleTimeZone + (-8000 * 3600, "America/Tijuana", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Tijuana", tz); + tz = new SimpleTimeZone + (-8000 * 3600, "PST", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("PST", tz); + timezones0.put("PST8PDT", tz); + timezones0.put("America/Dawson", tz); + timezones0.put("America/Los_Angeles", tz); + timezones0.put("America/Vancouver", tz); + timezones0.put("America/Whitehorse", tz); + timezones0.put("US/Pacific-New", tz); + tz = new SimpleTimeZone(-8000 * 3600, "Pacific/Pitcairn"); + timezones0.put("Pacific/Pitcairn", tz); + tz = new SimpleTimeZone + (-7000 * 3600, "America/Chihuahua", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Chihuahua", tz); + timezones0.put("America/Mazatlan", tz); + tz = new SimpleTimeZone(-7000 * 3600, "MST7"); + timezones0.put("MST7", tz); + timezones0.put("PNT", tz); + timezones0.put("America/Dawson_Creek", tz); + timezones0.put("America/Hermosillo", tz); + timezones0.put("America/Phoenix", tz); + tz = new SimpleTimeZone + (-7000 * 3600, "MST", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("MST", tz); + timezones0.put("MST7MDT", tz); + timezones0.put("America/Boise", tz); + timezones0.put("America/Cambridge_Bay", tz); + timezones0.put("America/Denver", tz); + timezones0.put("America/Edmonton", tz); + timezones0.put("America/Inuvik", tz); + timezones0.put("America/Shiprock", tz); + timezones0.put("America/Yellowknife", tz); + tz = new SimpleTimeZone + (-6000 * 3600, "America/Cancun", + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Cancun", tz); + timezones0.put("America/Merida", tz); + timezones0.put("America/Mexico_City", tz); + timezones0.put("America/Monterrey", tz); + tz = new SimpleTimeZone(-6000 * 3600, "America/Belize"); + timezones0.put("America/Belize", tz); + timezones0.put("America/Costa_Rica", tz); + timezones0.put("America/El_Salvador", tz); + timezones0.put("America/Guatemala", tz); + timezones0.put("America/Managua", tz); + timezones0.put("America/Regina", tz); + timezones0.put("America/Swift_Current", tz); + timezones0.put("America/Tegucigalpa", tz); + timezones0.put("Pacific/Galapagos", tz); + tz = new SimpleTimeZone + (-6000 * 3600, "CST", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("CST", tz); + timezones0.put("CST6CDT", tz); + timezones0.put("America/Chicago", tz); + timezones0.put("America/Indiana/Knox", tz); + timezones0.put("America/Indiana/Petersburg", tz); + timezones0.put("America/Indiana/Vincennes", tz); + timezones0.put("America/Menominee", tz); + timezones0.put("America/North_Dakota/Center", tz); + timezones0.put("America/North_Dakota/New_Salem", tz); + timezones0.put("America/Rainy_River", tz); + timezones0.put("America/Rankin_Inlet", tz); + timezones0.put("America/Winnipeg", tz); + tz = new SimpleTimeZone + (-6000 * 3600, "Pacific/Easter", + Calendar.OCTOBER, 2, Calendar.SATURDAY, 22000 * 3600, + Calendar.MARCH, 2, Calendar.SATURDAY, 22000 * 3600); + timezones0.put("Pacific/Easter", tz); + tz = new SimpleTimeZone(-5000 * 3600, "EST5"); + timezones0.put("EST5", tz); + timezones0.put("IET", tz); + timezones0.put("America/Atikokan", tz); + timezones0.put("America/Bogota", tz); + timezones0.put("America/Cayman", tz); + timezones0.put("America/Eirunepe", tz); + timezones0.put("America/Guayaquil", tz); + timezones0.put("America/Jamaica", tz); + timezones0.put("America/Lima", tz); + timezones0.put("America/Panama", tz); + timezones0.put("America/Rio_Branco", tz); + tz = new SimpleTimeZone + (-5000 * 3600, "America/Havana", + Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600); + timezones0.put("America/Havana", tz); + tz = new SimpleTimeZone + (-5000 * 3600, "America/Grand_Turk", + Calendar.APRIL, 1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Grand_Turk", tz); + timezones0.put("America/Port-au-Prince", tz); + tz = new SimpleTimeZone + (-5000 * 3600, "EST", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("EST", tz); + timezones0.put("EST5EDT", tz); + timezones0.put("America/Detroit", tz); + timezones0.put("America/Indiana/Indianapolis", tz); + timezones0.put("America/Indiana/Marengo", tz); + timezones0.put("America/Indiana/Vevay", tz); + timezones0.put("America/Iqaluit", tz); + timezones0.put("America/Kentucky/Louisville", tz); + timezones0.put("America/Kentucky/Monticello", tz); + timezones0.put("America/Montreal", tz); + timezones0.put("America/Nassau", tz); + timezones0.put("America/New_York", tz); + timezones0.put("America/Nipigon", tz); + timezones0.put("America/Pangnirtung", tz); + timezones0.put("America/Thunder_Bay", tz); + timezones0.put("America/Toronto", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Asuncion", + Calendar.OCTOBER, 3, Calendar.SUNDAY, 0 * 3600, + Calendar.MARCH, 2, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Asuncion", tz); + tz = new SimpleTimeZone(-4000 * 3600, "PRT"); + timezones0.put("PRT", tz); + timezones0.put("America/Anguilla", tz); + timezones0.put("America/Antigua", tz); + timezones0.put("America/Aruba", tz); + timezones0.put("America/Barbados", tz); + timezones0.put("America/Blanc-Sablon", tz); + timezones0.put("America/Boa_Vista", tz); + timezones0.put("America/Caracas", tz); + timezones0.put("America/Curacao", tz); + timezones0.put("America/Dominica", tz); + timezones0.put("America/Grenada", tz); + timezones0.put("America/Guadeloupe", tz); + timezones0.put("America/Guyana", tz); + timezones0.put("America/La_Paz", tz); + timezones0.put("America/Manaus", tz); + timezones0.put("America/Martinique", tz); + timezones0.put("America/Montserrat", tz); + timezones0.put("America/Port_of_Spain", tz); + timezones0.put("America/Porto_Velho", tz); + timezones0.put("America/Puerto_Rico", tz); + timezones0.put("America/Santo_Domingo", tz); + timezones0.put("America/St_Kitts", tz); + timezones0.put("America/St_Lucia", tz); + timezones0.put("America/St_Thomas", tz); + timezones0.put("America/St_Vincent", tz); + timezones0.put("America/Tortola", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Campo_Grande", + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 0 * 3600, + Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Campo_Grande", tz); + timezones0.put("America/Cuiaba", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Goose_Bay", + Calendar.MARCH, 2, Calendar.SUNDAY, 60000, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 60000); + timezones0.put("America/Goose_Bay", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Glace_Bay", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Glace_Bay", tz); + timezones0.put("America/Halifax", tz); + timezones0.put("America/Moncton", tz); + timezones0.put("America/Thule", tz); + timezones0.put("Atlantic/Bermuda", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "America/Santiago", + Calendar.OCTOBER, 9, -Calendar.SUNDAY, 0 * 3600, + Calendar.MARCH, 9, -Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Santiago", tz); + timezones0.put("Antarctica/Palmer", tz); + tz = new SimpleTimeZone + (-4000 * 3600, "Atlantic/Stanley", + Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.APRIL, 3, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Atlantic/Stanley", tz); + tz = new SimpleTimeZone + (-3500 * 3600, "CNT", + Calendar.MARCH, 2, Calendar.SUNDAY, 60000, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 60000); + timezones0.put("CNT", tz); + timezones0.put("America/St_Johns", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Godthab", + Calendar.MARCH, 30, -Calendar.SATURDAY, 22000 * 3600, + Calendar.OCTOBER, 30, -Calendar.SATURDAY, 23000 * 3600); + timezones0.put("America/Godthab", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Miquelon", + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600, + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Miquelon", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Montevideo", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, 2, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("America/Montevideo", tz); + tz = new SimpleTimeZone + (-3000 * 3600, "America/Sao_Paulo", + Calendar.NOVEMBER, 1, Calendar.SUNDAY, 0 * 3600, + Calendar.FEBRUARY, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("America/Sao_Paulo", tz); + tz = new SimpleTimeZone(-3000 * 3600, "AGT"); + timezones0.put("AGT", tz); + timezones0.put("America/Araguaina", tz); + timezones0.put("America/Argentina/Buenos_Aires", tz); + timezones0.put("America/Argentina/Catamarca", tz); + timezones0.put("America/Argentina/Cordoba", tz); + timezones0.put("America/Argentina/Jujuy", tz); + timezones0.put("America/Argentina/La_Rioja", tz); + timezones0.put("America/Argentina/Mendoza", tz); + timezones0.put("America/Argentina/Rio_Gallegos", tz); + timezones0.put("America/Argentina/San_Juan", tz); + timezones0.put("America/Argentina/Tucuman", tz); + timezones0.put("America/Argentina/Ushuaia", tz); + timezones0.put("America/Bahia", tz); + timezones0.put("America/Belem", tz); + timezones0.put("America/Cayenne", tz); + timezones0.put("America/Fortaleza", tz); + timezones0.put("America/Maceio", tz); + timezones0.put("America/Paramaribo", tz); + timezones0.put("America/Recife", tz); + timezones0.put("Antarctica/Rothera", tz); + tz = new SimpleTimeZone(-2000 * 3600, "America/Noronha"); + timezones0.put("America/Noronha", tz); + timezones0.put("Atlantic/South_Georgia", tz); + tz = new SimpleTimeZone + (-1000 * 3600, "America/Scoresbysund", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 1000 * 3600); + timezones0.put("America/Scoresbysund", tz); + timezones0.put("Atlantic/Azores", tz); + tz = new SimpleTimeZone(-1000 * 3600, "Atlantic/Cape_Verde"); + timezones0.put("Atlantic/Cape_Verde", tz); + tz = new SimpleTimeZone(0 * 3600, "GMT"); + timezones0.put("GMT", tz); + timezones0.put("UTC", tz); + timezones0.put("Africa/Abidjan", tz); + timezones0.put("Africa/Accra", tz); + timezones0.put("Africa/Bamako", tz); + timezones0.put("Africa/Banjul", tz); + timezones0.put("Africa/Bissau", tz); + timezones0.put("Africa/Casablanca", tz); + timezones0.put("Africa/Conakry", tz); + timezones0.put("Africa/Dakar", tz); + timezones0.put("Africa/El_Aaiun", tz); + timezones0.put("Africa/Freetown", tz); + timezones0.put("Africa/Lome", tz); + timezones0.put("Africa/Monrovia", tz); + timezones0.put("Africa/Nouakchott", tz); + timezones0.put("Africa/Ouagadougou", tz); + timezones0.put("Africa/Sao_Tome", tz); + timezones0.put("America/Danmarkshavn", tz); + timezones0.put("Atlantic/Reykjavik", tz); + timezones0.put("Atlantic/St_Helena", tz); + tz = new SimpleTimeZone + (0 * 3600, "WET", + Calendar.MARCH, -1, Calendar.SUNDAY, 1000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("WET", tz); + timezones0.put("Atlantic/Canary", tz); + timezones0.put("Atlantic/Faroe", tz); + timezones0.put("Atlantic/Madeira", tz); + timezones0.put("Europe/Dublin", tz); + timezones0.put("Europe/Guernsey", tz); + timezones0.put("Europe/Isle_of_Man", tz); + timezones0.put("Europe/Jersey", tz); + timezones0.put("Europe/Lisbon", tz); + timezones0.put("Europe/London", tz); + tz = new SimpleTimeZone(1000 * 3600, "Africa/Algiers"); + timezones0.put("Africa/Algiers", tz); + timezones0.put("Africa/Bangui", tz); + timezones0.put("Africa/Brazzaville", tz); + timezones0.put("Africa/Douala", tz); + timezones0.put("Africa/Kinshasa", tz); + timezones0.put("Africa/Lagos", tz); + timezones0.put("Africa/Libreville", tz); + timezones0.put("Africa/Luanda", tz); + timezones0.put("Africa/Malabo", tz); + timezones0.put("Africa/Ndjamena", tz); + timezones0.put("Africa/Niamey", tz); + timezones0.put("Africa/Porto-Novo", tz); + tz = new SimpleTimeZone + (1000 * 3600, "Africa/Windhoek", + Calendar.SEPTEMBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.APRIL, 1, Calendar.SUNDAY, 2000 * 3600); + timezones0.put("Africa/Windhoek", tz); + tz = new SimpleTimeZone + (1000 * 3600, "CET", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("CET", tz); + timezones0.put("ECT", tz); + timezones0.put("MET", tz); + timezones0.put("Africa/Ceuta", tz); + timezones0.put("Africa/Tunis", tz); + timezones0.put("Arctic/Longyearbyen", tz); + timezones0.put("Atlantic/Jan_Mayen", tz); + timezones0.put("Europe/Amsterdam", tz); + timezones0.put("Europe/Andorra", tz); + timezones0.put("Europe/Belgrade", tz); + timezones0.put("Europe/Berlin", tz); + timezones0.put("Europe/Bratislava", tz); + timezones0.put("Europe/Brussels", tz); + timezones0.put("Europe/Budapest", tz); + timezones0.put("Europe/Copenhagen", tz); + timezones0.put("Europe/Gibraltar", tz); + timezones0.put("Europe/Ljubljana", tz); + timezones0.put("Europe/Luxembourg", tz); + timezones0.put("Europe/Madrid", tz); + timezones0.put("Europe/Malta", tz); + timezones0.put("Europe/Monaco", tz); + timezones0.put("Europe/Oslo", tz); + timezones0.put("Europe/Paris", tz); + timezones0.put("Europe/Podgorica", tz); + timezones0.put("Europe/Prague", tz); + timezones0.put("Europe/Rome", tz); + timezones0.put("Europe/San_Marino", tz); + timezones0.put("Europe/Sarajevo", tz); + timezones0.put("Europe/Skopje", tz); + timezones0.put("Europe/Stockholm", tz); + timezones0.put("Europe/Tirane", tz); + timezones0.put("Europe/Vaduz", tz); + timezones0.put("Europe/Vatican", tz); + timezones0.put("Europe/Vienna", tz); + timezones0.put("Europe/Warsaw", tz); + timezones0.put("Europe/Zagreb", tz); + timezones0.put("Europe/Zurich", tz); + tz = new SimpleTimeZone + (2000 * 3600, "ART", + Calendar.APRIL, -1, Calendar.FRIDAY, 0 * 3600, + Calendar.SEPTEMBER, -1, Calendar.THURSDAY, 24000 * 3600); + timezones0.put("ART", tz); + timezones0.put("Africa/Cairo", tz); + tz = new SimpleTimeZone(2000 * 3600, "CAT"); + timezones0.put("CAT", tz); + timezones0.put("Africa/Blantyre", tz); + timezones0.put("Africa/Bujumbura", tz); + timezones0.put("Africa/Gaborone", tz); + timezones0.put("Africa/Harare", tz); + timezones0.put("Africa/Johannesburg", tz); + timezones0.put("Africa/Kigali", tz); + timezones0.put("Africa/Lubumbashi", tz); + timezones0.put("Africa/Lusaka", tz); + timezones0.put("Africa/Maputo", tz); + timezones0.put("Africa/Maseru", tz); + timezones0.put("Africa/Mbabane", tz); + timezones0.put("Africa/Tripoli", tz); + timezones0.put("Asia/Jerusalem", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Amman", + Calendar.MARCH, -1, Calendar.THURSDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.FRIDAY, 1000 * 3600); + timezones0.put("Asia/Amman", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Beirut", + Calendar.MARCH, -1, Calendar.SUNDAY, 0 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 0 * 3600); + timezones0.put("Asia/Beirut", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Damascus", + Calendar.APRIL, 1, 0, 0 * 3600, + Calendar.OCTOBER, 1, 0, 0 * 3600); + timezones0.put("Asia/Damascus", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Asia/Gaza", + Calendar.APRIL, 1, 0, 0 * 3600, + Calendar.OCTOBER, 3, Calendar.FRIDAY, 0 * 3600); + timezones0.put("Asia/Gaza", tz); + tz = new SimpleTimeZone + (2000 * 3600, "EET", + Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 4000 * 3600); + timezones0.put("EET", tz); + timezones0.put("Asia/Istanbul", tz); + timezones0.put("Asia/Nicosia", tz); + timezones0.put("Europe/Athens", tz); + timezones0.put("Europe/Bucharest", tz); + timezones0.put("Europe/Chisinau", tz); + timezones0.put("Europe/Helsinki", tz); + timezones0.put("Europe/Istanbul", tz); + timezones0.put("Europe/Kiev", tz); + timezones0.put("Europe/Mariehamn", tz); + timezones0.put("Europe/Nicosia", tz); + timezones0.put("Europe/Riga", tz); + timezones0.put("Europe/Simferopol", tz); + timezones0.put("Europe/Sofia", tz); + timezones0.put("Europe/Tallinn", tz); + timezones0.put("Europe/Uzhgorod", tz); + timezones0.put("Europe/Vilnius", tz); + timezones0.put("Europe/Zaporozhye", tz); + tz = new SimpleTimeZone + (2000 * 3600, "Europe/Kaliningrad", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Europe/Kaliningrad", tz); + timezones0.put("Europe/Minsk", tz); + tz = new SimpleTimeZone + (3000 * 3600, "Asia/Baghdad", + Calendar.APRIL, 1, 0, 3000 * 3600, + Calendar.OCTOBER, 1, 0, 4000 * 3600); + timezones0.put("Asia/Baghdad", tz); + tz = new SimpleTimeZone + (3000 * 3600, "Europe/Moscow", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Europe/Moscow", tz); + timezones0.put("Europe/Volgograd", tz); + tz = new SimpleTimeZone(3000 * 3600, "EAT"); + timezones0.put("EAT", tz); + timezones0.put("Africa/Addis_Ababa", tz); + timezones0.put("Africa/Asmara", tz); + timezones0.put("Africa/Dar_es_Salaam", tz); + timezones0.put("Africa/Djibouti", tz); + timezones0.put("Africa/Kampala", tz); + timezones0.put("Africa/Khartoum", tz); + timezones0.put("Africa/Mogadishu", tz); + timezones0.put("Africa/Nairobi", tz); + timezones0.put("Antarctica/Syowa", tz); + timezones0.put("Asia/Aden", tz); + timezones0.put("Asia/Bahrain", tz); + timezones0.put("Asia/Kuwait", tz); + timezones0.put("Asia/Qatar", tz); + timezones0.put("Asia/Riyadh", tz); + timezones0.put("Indian/Antananarivo", tz); + timezones0.put("Indian/Comoro", tz); + timezones0.put("Indian/Mayotte", tz); + tz = new SimpleTimeZone(3500 * 3600, "Asia/Tehran"); + timezones0.put("Asia/Tehran", tz); + tz = new SimpleTimeZone + (4000 * 3600, "Asia/Baku", + Calendar.MARCH, -1, Calendar.SUNDAY, 4000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 5000 * 3600); + timezones0.put("Asia/Baku", tz); + tz = new SimpleTimeZone + (4000 * 3600, "Asia/Yerevan", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Yerevan", tz); + timezones0.put("Europe/Samara", tz); + tz = new SimpleTimeZone(4000 * 3600, "NET"); + timezones0.put("NET", tz); + timezones0.put("Asia/Dubai", tz); + timezones0.put("Asia/Muscat", tz); + timezones0.put("Asia/Tbilisi", tz); + timezones0.put("Indian/Mahe", tz); + timezones0.put("Indian/Mauritius", tz); + timezones0.put("Indian/Reunion", tz); + tz = new SimpleTimeZone(4500 * 3600, "Asia/Kabul"); + timezones0.put("Asia/Kabul", tz); + tz = new SimpleTimeZone + (5000 * 3600, "Asia/Yekaterinburg", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Yekaterinburg", tz); + tz = new SimpleTimeZone(5000 * 3600, "PLT"); + timezones0.put("PLT", tz); + timezones0.put("Asia/Aqtau", tz); + timezones0.put("Asia/Aqtobe", tz); + timezones0.put("Asia/Ashgabat", tz); + timezones0.put("Asia/Dushanbe", tz); + timezones0.put("Asia/Karachi", tz); + timezones0.put("Asia/Oral", tz); + timezones0.put("Asia/Samarkand", tz); + timezones0.put("Asia/Tashkent", tz); + timezones0.put("Indian/Kerguelen", tz); + timezones0.put("Indian/Maldives", tz); + tz = new SimpleTimeZone(5500 * 3600, "BST"); + timezones0.put("BST", tz); + timezones0.put("IST", tz); + timezones0.put("Asia/Calcutta", tz); + timezones0.put("Asia/Colombo", tz); + tz = new SimpleTimeZone(5750 * 3600, "Asia/Katmandu"); + timezones0.put("Asia/Katmandu", tz); + tz = new SimpleTimeZone(6000 * 3600, "Antarctica/Mawson"); + timezones0.put("Antarctica/Mawson", tz); + timezones0.put("Antarctica/Vostok", tz); + timezones0.put("Asia/Almaty", tz); + timezones0.put("Asia/Bishkek", tz); + timezones0.put("Asia/Dhaka", tz); + timezones0.put("Asia/Qyzylorda", tz); + timezones0.put("Asia/Thimphu", tz); + timezones0.put("Indian/Chagos", tz); + tz = new SimpleTimeZone + (6000 * 3600, "Asia/Novosibirsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Novosibirsk", tz); + timezones0.put("Asia/Omsk", tz); + tz = new SimpleTimeZone(6500 * 3600, "Asia/Rangoon"); + timezones0.put("Asia/Rangoon", tz); + timezones0.put("Indian/Cocos", tz); + tz = new SimpleTimeZone(7000 * 3600, "VST"); + timezones0.put("VST", tz); + timezones0.put("Antarctica/Davis", tz); + timezones0.put("Asia/Bangkok", tz); + timezones0.put("Asia/Jakarta", tz); + timezones0.put("Asia/Phnom_Penh", tz); + timezones0.put("Asia/Pontianak", tz); + timezones0.put("Asia/Saigon", tz); + timezones0.put("Asia/Vientiane", tz); + timezones0.put("Indian/Christmas", tz); + tz = new SimpleTimeZone + (7000 * 3600, "Asia/Hovd", + Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600, + Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600); + timezones0.put("Asia/Hovd", tz); + tz = new SimpleTimeZone + (7000 * 3600, "Asia/Krasnoyarsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Krasnoyarsk", tz); + tz = new SimpleTimeZone(8000 * 3600, "CTT"); + timezones0.put("CTT", tz); + timezones0.put("Antarctica/Casey", tz); + timezones0.put("Asia/Brunei", tz); + timezones0.put("Asia/Chongqing", tz); + timezones0.put("Asia/Harbin", tz); + timezones0.put("Asia/Hong_Kong", tz); + timezones0.put("Asia/Kashgar", tz); + timezones0.put("Asia/Kuala_Lumpur", tz); + timezones0.put("Asia/Kuching", tz); + timezones0.put("Asia/Macau", tz); + timezones0.put("Asia/Makassar", tz); + timezones0.put("Asia/Manila", tz); + timezones0.put("Asia/Shanghai", tz); + timezones0.put("Asia/Singapore", tz); + timezones0.put("Asia/Taipei", tz); + timezones0.put("Asia/Urumqi", tz); + timezones0.put("Australia/Perth", tz); + tz = new SimpleTimeZone + (8000 * 3600, "Asia/Irkutsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Irkutsk", tz); + tz = new SimpleTimeZone + (8000 * 3600, "Asia/Ulaanbaatar", + Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600, + Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600); + timezones0.put("Asia/Ulaanbaatar", tz); + tz = new SimpleTimeZone(8750 * 3600, "Australia/Eucla"); + timezones0.put("Australia/Eucla", tz); + tz = new SimpleTimeZone + (9000 * 3600, "Asia/Choibalsan", + Calendar.MARCH, -1, Calendar.SATURDAY, 2000 * 3600, + Calendar.SEPTEMBER, -1, Calendar.SATURDAY, 2000 * 3600); + timezones0.put("Asia/Choibalsan", tz); + tz = new SimpleTimeZone(9000 * 3600, "JST"); + timezones0.put("JST", tz); + timezones0.put("Asia/Dili", tz); + timezones0.put("Asia/Jayapura", tz); + timezones0.put("Asia/Pyongyang", tz); + timezones0.put("Asia/Seoul", tz); + timezones0.put("Asia/Tokyo", tz); + timezones0.put("Pacific/Palau", tz); + tz = new SimpleTimeZone + (9000 * 3600, "Asia/Yakutsk", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Yakutsk", tz); + tz = new SimpleTimeZone + (9500 * 3600, "Australia/Adelaide", + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Australia/Adelaide", tz); + timezones0.put("Australia/Broken_Hill", tz); + tz = new SimpleTimeZone(9500 * 3600, "ACT"); + timezones0.put("ACT", tz); + timezones0.put("Australia/Darwin", tz); + tz = new SimpleTimeZone(10000 * 3600, "Antarctica/DumontDUrville"); + timezones0.put("Antarctica/DumontDUrville", tz); + timezones0.put("Australia/Brisbane", tz); + timezones0.put("Australia/Lindeman", tz); + timezones0.put("Pacific/Guam", tz); + timezones0.put("Pacific/Port_Moresby", tz); + timezones0.put("Pacific/Saipan", tz); + timezones0.put("Pacific/Truk", tz); + tz = new SimpleTimeZone + (10000 * 3600, "Asia/Sakhalin", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Sakhalin", tz); + timezones0.put("Asia/Vladivostok", tz); + tz = new SimpleTimeZone + (10000 * 3600, "Australia/Currie", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Australia/Currie", tz); + timezones0.put("Australia/Hobart", tz); + tz = new SimpleTimeZone + (10000 * 3600, "AET", + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("AET", tz); + timezones0.put("Australia/Melbourne", tz); + timezones0.put("Australia/Sydney", tz); + tz = new SimpleTimeZone + (10500 * 3600, "Australia/Lord_Howe", + Calendar.OCTOBER, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, 500 * 3600); + timezones0.put("Australia/Lord_Howe", tz); + tz = new SimpleTimeZone + (11000 * 3600, "Asia/Magadan", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Magadan", tz); + tz = new SimpleTimeZone(11000 * 3600, "SST"); + timezones0.put("SST", tz); + timezones0.put("Pacific/Efate", tz); + timezones0.put("Pacific/Guadalcanal", tz); + timezones0.put("Pacific/Kosrae", tz); + timezones0.put("Pacific/Noumea", tz); + timezones0.put("Pacific/Ponape", tz); + tz = new SimpleTimeZone(11500 * 3600, "Pacific/Norfolk"); + timezones0.put("Pacific/Norfolk", tz); + tz = new SimpleTimeZone + (12000 * 3600, "NST", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2000 * 3600, + Calendar.MARCH, 3, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("NST", tz); + timezones0.put("Antarctica/McMurdo", tz); + timezones0.put("Antarctica/South_Pole", tz); + timezones0.put("Pacific/Auckland", tz); + tz = new SimpleTimeZone + (12000 * 3600, "Asia/Anadyr", + Calendar.MARCH, -1, Calendar.SUNDAY, 2000 * 3600, + Calendar.OCTOBER, -1, Calendar.SUNDAY, 3000 * 3600); + timezones0.put("Asia/Anadyr", tz); + timezones0.put("Asia/Kamchatka", tz); + tz = new SimpleTimeZone(12000 * 3600, "Pacific/Fiji"); + timezones0.put("Pacific/Fiji", tz); + timezones0.put("Pacific/Funafuti", tz); + timezones0.put("Pacific/Kwajalein", tz); + timezones0.put("Pacific/Majuro", tz); + timezones0.put("Pacific/Nauru", tz); + timezones0.put("Pacific/Tarawa", tz); + timezones0.put("Pacific/Wake", tz); + timezones0.put("Pacific/Wallis", tz); + tz = new SimpleTimeZone + (12750 * 3600, "Pacific/Chatham", + Calendar.OCTOBER, 1, Calendar.SUNDAY, 2750 * 3600, + Calendar.MARCH, 3, Calendar.SUNDAY, 3750 * 3600); + timezones0.put("Pacific/Chatham", tz); + tz = new SimpleTimeZone(13000 * 3600, "Pacific/Enderbury"); + timezones0.put("Pacific/Enderbury", tz); + timezones0.put("Pacific/Tongatapu", tz); + tz = new SimpleTimeZone(14000 * 3600, "Pacific/Kiritimati"); + timezones0.put("Pacific/Kiritimati", tz); + } + return timezones0; + } + + /** + * Maps a time zone name (with optional GMT offset and daylight time + * zone name) to one of the known time zones. This method called + * with the result of System.getProperty("user.timezone") + * or getDefaultTimeZoneId(). Note that giving one of + * the standard tz data names from ftp://elsie.nci.nih.gov/pub/ is + * preferred. + * The time zone name can be given as follows: + * (standard zone name)[(GMT offset)[(DST zone name)[DST offset]]] + * + *

+ * If only a (standard zone name) is given (no numbers in the + * String) then it gets mapped directly to the TimeZone with that + * name, if that fails null is returned. + *

+ * Alternately, a POSIX-style TZ string can be given, defining the time zone: + * std offset dst offset,date/time,date/time + * See the glibc manual, or the man page for tzset for details + * of this format. + *

+ * A GMT offset is the offset to add to the local time to get GMT. + * If a (GMT offset) is included (either in seconds or hours) then + * an attempt is made to find a TimeZone name matching both the name + * and the offset (that doesn't observe daylight time, if the + * timezone observes daylight time then you must include a daylight + * time zone name after the offset), if that fails then a TimeZone + * with the given GMT offset is returned (whether or not the + * TimeZone observes daylight time is ignored), if that also fails + * the GMT TimeZone is returned. + *

+ * If the String ends with (GMT offset)(daylight time zone name) + * then an attempt is made to find a TimeZone with the given name and + * GMT offset that also observes (the daylight time zone name is not + * currently used in any other way), if that fails a TimeZone with + * the given GMT offset that observes daylight time is returned, if + * that also fails the GMT TimeZone is returned. + *

+ * Examples: In Chicago, the time zone id could be "CST6CDT", but + * the preferred name would be "America/Chicago". In Indianapolis + * (which does not have Daylight Savings Time) the string could be + * "EST5", but the preferred name would be "America/Indianapolis". + * The standard time zone name for The Netherlands is "Europe/Amsterdam", + * but can also be given as "CET-1CEST". + */ + static TimeZone getDefaultTimeZone(String sysTimeZoneId) + { + String stdName = null; + int stdOffs; + int dstOffs; + try + { + int idLength = sysTimeZoneId.length(); + + int index = 0; + int prevIndex; + char c; + + // get std + do + c = sysTimeZoneId.charAt(index); + while (c != '+' && c != '-' && c != ',' && c != ':' + && ! Character.isDigit(c) && c != '\0' && ++index < idLength); + + if (index >= idLength) + return getTimeZoneInternal(sysTimeZoneId); + + stdName = sysTimeZoneId.substring(0, index); + prevIndex = index; + + // get the std offset + do + c = sysTimeZoneId.charAt(index++); + while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c)) + && index < idLength); + if (index < idLength) + index--; + + { // convert the dst string to a millis number + String offset = sysTimeZoneId.substring(prevIndex, index); + prevIndex = index; + + if (offset.charAt(0) == '+' || offset.charAt(0) == '-') + stdOffs = parseTime(offset.substring(1)); + else + stdOffs = parseTime(offset); + + if (offset.charAt(0) == '-') + stdOffs = -stdOffs; + + // TZ timezone offsets are positive when WEST of the meridian. + stdOffs = -stdOffs; + } + + // Done yet? (Format: std offset) + if (index >= idLength) + { + // Do we have an existing timezone with that name and offset? + TimeZone tz = getTimeZoneInternal(stdName); + if (tz != null) + if (tz.getRawOffset() == stdOffs) + return tz; + + // Custom then. + return new SimpleTimeZone(stdOffs, stdName); + } + + // get dst + do + c = sysTimeZoneId.charAt(index); + while (c != '+' && c != '-' && c != ',' && c != ':' + && ! Character.isDigit(c) && c != '\0' && ++index < idLength); + + // Done yet? (Format: std offset dst) + if (index >= idLength) + { + // Do we have an existing timezone with that name and offset + // which has DST? + TimeZone tz = getTimeZoneInternal(stdName); + if (tz != null) + if (tz.getRawOffset() == stdOffs && tz.useDaylightTime()) + return tz; + + // Custom then. + return new SimpleTimeZone(stdOffs, stdName); + } + + // get the dst offset + prevIndex = index; + do + c = sysTimeZoneId.charAt(index++); + while ((c == '-' || c == '+' || c == ':' || Character.isDigit(c)) + && index < idLength); + if (index < idLength) + index--; + + if (index == prevIndex && (c == ',' || c == ';')) + { + // Missing dst offset defaults to one hour ahead of standard + // time. + dstOffs = stdOffs + 60 * 60 * 1000; + } + else + { // convert the dst string to a millis number + String offset = sysTimeZoneId.substring(prevIndex, index); + prevIndex = index; + + if (offset.charAt(0) == '+' || offset.charAt(0) == '-') + dstOffs = parseTime(offset.substring(1)); + else + dstOffs = parseTime(offset); + + if (offset.charAt(0) == '-') + dstOffs = -dstOffs; + + // TZ timezone offsets are positive when WEST of the meridian. + dstOffs = -dstOffs; + } + + // Done yet? (Format: std offset dst offset) + // FIXME: We don't support DST without a rule given. Should we? + if (index >= idLength) + { + // Time Zone existing with same name, dst and offsets? + TimeZone tz = getTimeZoneInternal(stdName); + if (tz != null) + if (tz.getRawOffset() == stdOffs && tz.useDaylightTime() + && tz.getDSTSavings() == (dstOffs - stdOffs)) + return tz; + + return new SimpleTimeZone(stdOffs, stdName); + } + + // get the DST rule + if (sysTimeZoneId.charAt(index) == ',' + || sysTimeZoneId.charAt(index) == ';') + { + index++; + int offs = index; + while (sysTimeZoneId.charAt(index) != ',' + && sysTimeZoneId.charAt(index) != ';') + index++; + String startTime = sysTimeZoneId.substring(offs, index); + index++; + String endTime = sysTimeZoneId.substring(index); + + index = startTime.indexOf('/'); + int startMillis; + int endMillis; + String startDate; + String endDate; + if (index != -1) + { + startDate = startTime.substring(0, index); + startMillis = parseTime(startTime.substring(index + 1)); + } + else + { + startDate = startTime; + // if time isn't given, default to 2:00:00 AM. + startMillis = 2 * 60 * 60 * 1000; + } + index = endTime.indexOf('/'); + if (index != -1) + { + endDate = endTime.substring(0, index); + endMillis = parseTime(endTime.substring(index + 1)); + } + else + { + endDate = endTime; + // if time isn't given, default to 2:00:00 AM. + endMillis = 2 * 60 * 60 * 1000; + } + + int[] start = getDateParams(startDate); + int[] end = getDateParams(endDate); + return new SimpleTimeZone(stdOffs, stdName, start[0], start[1], + start[2], startMillis, end[0], end[1], + end[2], endMillis, (dstOffs - stdOffs)); + } + } + + // FIXME: Produce a warning here? + catch (/*IndexOutOfBounds*/Exception _) + { + } + /*catch (NumberFormatException _) + { + }*/ + + return null; + } + + /** + * Parses and returns the params for a POSIX TZ date field, + * in the format int[]{ month, day, dayOfWeek }, following the + * SimpleTimeZone constructor rules. + */ + private static int[] getDateParams(String date) + { + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int month; + + if (date.charAt(0) == 'M' || date.charAt(0) == 'm') + { + int day; + + // Month, week of month, day of week + month = Integer.parseInt(date.substring(1, date.indexOf('.'))); + int week = Integer.parseInt(date.substring(date.indexOf('.') + 1, + date.lastIndexOf('.'))); + int dayOfWeek = Integer.parseInt(date.substring(date.lastIndexOf('.') + + 1)); + if (week == 5) + day = -1; // last day of month is -1 in java, 5 in TZ + else + // first day of week starting on or after. + day = (week - 1) * 7 + 1; + + dayOfWeek++; // Java day of week is one-based, Sunday is first day. + month--; // Java month is zero-based. + return new int[] { month, day, dayOfWeek }; + } + + // julian day, either zero-based 0<=n<=365 (incl feb 29) + // or one-based 1<=n<=365 (no feb 29) + int julianDay; // Julian day, + + if (date.charAt(0) != 'J' || date.charAt(0) != 'j') + { + julianDay = Integer.parseInt(date.substring(1)); + julianDay++; // make 1-based + // Adjust day count to include feb 29. + dayCount = new int[] + { + 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 + }; + } + else + // 1-based julian day + julianDay = Integer.parseInt(date); + + int i = 11; + while (i > 0) + if (dayCount[i] < julianDay) + break; + else + i--; + julianDay -= dayCount[i]; + month = i; + return new int[] { month, julianDay, 0 }; + } + + /** + * Parses a time field hh[:mm[:ss]], returning the result + * in milliseconds. No leading sign. + */ + private static int parseTime(String time) + { + int millis = 0; + int i = 0; + + while (i < time.length()) + if (time.charAt(i) == ':') + break; + else + i++; + millis = 60 * 60 * 1000 * Integer.parseInt(time.substring(0, i)); + if (i >= time.length()) + return millis; + + int iprev = ++i; + while (i < time.length()) + if (time.charAt(i) == ':') + break; + else + i++; + millis += 60 * 1000 * Integer.parseInt(time.substring(iprev, i)); + if (i >= time.length()) + return millis; + + millis += 1000 * Integer.parseInt(time.substring(++i)); + return millis; + } + + /** + * Gets the time zone offset, for current date, modified in case of + * daylight savings. This is the offset to add to UTC to get the local + * time. + * @param era the era of the given date + * @param year the year of the given date + * @param month the month of the given date, 0 for January. + * @param day the day of month + * @param dayOfWeek the day of week + * @param milliseconds the millis in the day (in local standard time) + * @return the time zone offset in milliseconds. + */ + public abstract int getOffset(int era, int year, int month, + int day, int dayOfWeek, int milliseconds); + + /** + * Get the time zone offset for the specified date, modified in case of + * daylight savings. This is the offset to add to UTC to get the local + * time. + * @param date the date represented in millisecends + * since January 1, 1970 00:00:00 GMT. + * @since 1.4 + */ + public int getOffset(long date) + { + return (inDaylightTime(new Date(date)) + ? getRawOffset() + getDSTSavings() + : getRawOffset()); + } + + /** + * Gets the time zone offset, ignoring daylight savings. This is + * the offset to add to UTC to get the local time. + * @return the time zone offset in milliseconds. + */ + public abstract int getRawOffset(); + + /** + * Sets the time zone offset, ignoring daylight savings. This is + * the offset to add to UTC to get the local time. + * @param offsetMillis the time zone offset to GMT. + */ + public abstract void setRawOffset(int offsetMillis); + + /** + * Gets the identifier of this time zone. For instance, PST for + * Pacific Standard Time. + * @returns the ID of this time zone. + */ + public String getID() + { + return ID; + } + + /** + * Sets the identifier of this time zone. For instance, PST for + * Pacific Standard Time. + * @param id the new time zone ID. + * @throws NullPointerException if id is null + */ + public void setID(String id) + { + if (id == null) + throw new Exception/*NullPointerException*/("NullPointerException"); + + this.ID = id; + } + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be the long + * description of the timezone in the current locale. The name + * displayed will assume daylight savings time is not in effect. + * + * @return The name of the time zone. + */ + public final String getDisplayName() + { + return (getDisplayName(false, LONG, Locale.getDefault())); + } + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be the long + * description of the timezone in the specified locale. The name + * displayed will assume daylight savings time is not in effect. + * + * @param locale The locale for this timezone name. + * + * @return The name of the time zone. + */ + public final String getDisplayName(Locale locale) + { + return (getDisplayName(false, LONG, locale)); + } + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be of the + * specified type in the current locale. + * + * @param dst Whether or not daylight savings time is in effect. + * @param style LONG for a long name, SHORT for + * a short abbreviation. + * + * @return The name of the time zone. + */ + public final String getDisplayName(boolean dst, int style) + { + return (getDisplayName(dst, style, Locale.getDefault())); + } + + + /** + * This method returns a string name of the time zone suitable + * for displaying to the user. The string returned will be of the + * specified type in the specified locale. + * + * @param dst Whether or not daylight savings time is in effect. + * @param style LONG for a long name, SHORT for + * a short abbreviation. + * @param locale The locale for this timezone name. + * + * @return The name of the time zone. + */ + /*public String getDisplayName(boolean dst, int style, Locale locale) + { + DateFormatSymbols dfs; + try + { + dfs = new DateFormatSymbols(locale); + + // The format of the value returned is defined by us. + String[][]zoneinfo = dfs.getZoneStrings(); + for (int i = 0; i < zoneinfo.length; i++) + { + if (zoneinfo[i][0].equals(getID())) + { + if (!dst) + { + if (style == SHORT) + return (zoneinfo[i][2]); + else + return (zoneinfo[i][1]); + } + else + { + if (style == SHORT) + return (zoneinfo[i][4]); + else + return (zoneinfo[i][3]); + } + } + } + } + catch (MissingResourceException e) + { + } + + return getDefaultDisplayName(dst); + }*/ + + /*private String getDefaultDisplayName(boolean dst) + { + int offset = getRawOffset(); + if (dst && this instanceof SimpleTimeZone) + { + // ugly, but this is a design failure of the API: + // getDisplayName takes a dst parameter even though + // TimeZone knows nothing about daylight saving offsets. + offset += ((SimpleTimeZone) this).getDSTSavings(); + } + + CPStringBuilder sb = new CPStringBuilder(9); + sb.append("GMT"); + + offset = offset / (1000 * 60); + int hours = Math.abs(offset) / 60; + int minutes = Math.abs(offset) % 60; + + if (minutes != 0 || hours != 0) + { + sb.append(offset >= 0 ? '+' : '-'); + sb.append((char) ('0' + hours / 10)); + sb.append((char) ('0' + hours % 10)); + sb.append(':'); + sb.append((char) ('0' + minutes / 10)); + sb.append((char) ('0' + minutes % 10)); + } + + return sb.toString(); + }*/ + + /** + * Returns true, if this time zone uses Daylight Savings Time. + */ + public abstract boolean useDaylightTime(); + + /** + * Returns true, if the given date is in Daylight Savings Time in this + * time zone. + * @param date the given Date. + */ + public abstract boolean inDaylightTime(Date date); + + /** + * Gets the daylight savings offset. This is a positive offset in + * milliseconds with respect to standard time. Typically this + * is one hour, but for some time zones this may be half an our. + *

The default implementation returns 3600000 milliseconds + * (one hour) if the time zone uses daylight savings time + * (as specified by {@link #useDaylightTime()}), otherwise + * it returns 0. + * @return the daylight savings offset in milliseconds. + * @since 1.4 + */ + public int getDSTSavings () + { + return useDaylightTime () ? 3600000 : 0; + } + + /** + * Gets the TimeZone for the given ID. + * @param ID the time zone identifier. + * @return The time zone for the identifier or GMT, if no such time + * zone exists. + */ + private static TimeZone getTimeZoneInternal(String ID) + { + // First check timezones hash + TimeZone tz = null; + TimeZone tznew = null; + for (int pass = 0; pass < 2; pass++) + { + synchronized (TimeZone.class) + { + tz = (TimeZone) timezones().get(ID); + if (tz != null) + { + if (!tz.getID().equals(ID)) + { + // We always return a timezone with the requested ID. + // This is the same behaviour as with JDK1.2. + tz = (TimeZone) tz.clone(); + tz.setID(ID); + // We also save the alias, so that we return the same + // object again if getTimeZone is called with the same + // alias. + timezones().put(ID, tz); + } + return tz; + } + else if (tznew != null) + { + timezones().put(ID, tznew); + return tznew; + } + } + + if (pass == 1 || zoneinfo_dir == null) + return null; + + // aliases0 is never changing after first timezones(), so should + // be safe without synchronization. + String zonename = (String) aliases0.get(ID); + if (zonename == null) + zonename = ID; + + // Read the file outside of the critical section, it is expensive. + tznew = ZoneInfo.readTZFile (ID, zoneinfo_dir + + File.separatorChar + zonename); + if (tznew == null) + return null; + } + + return null; + } + + /** + * Gets the TimeZone for the given ID. + * @param ID the time zone identifier. + * @return The time zone for the identifier or GMT, if no such time + * zone exists. + */ + public static TimeZone getTimeZone(String ID) + { + // Check for custom IDs first + if (ID.startsWith("GMT") && ID.length() > 3) + { + int pos = 3; + int offset_direction = 1; + + if (ID.charAt(pos) == '-') + { + offset_direction = -1; + pos++; + } + else if (ID.charAt(pos) == '+') + { + pos++; + } + + try + { + int hour, minute; + + String offset_str = ID.substring(pos); + int idx = offset_str.indexOf(":"); + if (idx != -1) + { + hour = Integer.parseInt(offset_str.substring(0, idx)); + minute = Integer.parseInt(offset_str.substring(idx + 1)); + } + else + { + int offset_length = offset_str.length(); + if (offset_length <= 2) + { + // Only hour + hour = Integer.parseInt(offset_str); + minute = 0; + } + else + { + // hour and minute, not separated by colon + hour = Integer.parseInt + (offset_str.substring(0, offset_length - 2)); + minute = Integer.parseInt + (offset_str.substring(offset_length - 2)); + } + } + + // Custom IDs have to be normalized + /*CPStringBuilder sb = new CPStringBuilder(9); + sb.append("GMT"); + + sb.append(offset_direction >= 0 ? '+' : '-'); + sb.append((char) ('0' + hour / 10)); + sb.append((char) ('0' + hour % 10)); + sb.append(':'); + sb.append((char) ('0' + minute / 10)); + sb.append((char) ('0' + minute % 10));*/ + ID = "GMT" + (offset_direction >= 0 ? "+" : "-") + (char) ('0' + hour / 10) + + (char) ('0' + hour % 10) + ":" + (char) ('0' + minute / 10) + (char) ('0' + minute % 10);//sb.toString(); + + return new SimpleTimeZone((hour * (60 * 60 * 1000) + + minute * (60 * 1000)) + * offset_direction, ID); + } + catch (/*NumberFormat*/Exception e) + { + } + } + + TimeZone tz = getTimeZoneInternal(ID); + if (tz != null) + return tz; + + return new SimpleTimeZone(0, "GMT"); + } + + /** + * Gets the available IDs according to the given time zone + * offset. + * @param rawOffset the given time zone GMT offset. + * @return An array of IDs, where the time zone has the specified GMT + * offset. For example {"Phoenix", "Denver"}, since both have + * GMT-07:00, but differ in daylight savings behaviour. + */ + public static String[] getAvailableIDs(int rawOffset) + { + synchronized (TimeZone.class) + { + HashMap h = timezones(); + int count = 0; + if (zoneinfo_dir == null) + { + Iterator iter = h.entrySet().iterator(); + while (iter.hasNext()) + { + // Don't iterate the values, since we want to count + // doubled values (aliases) + Map.Entry entry = (Map.Entry) iter.next(); + if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset) + count++; + } + + String[] ids = new String[count]; + count = 0; + iter = h.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry entry = (Map.Entry) iter.next(); + if (((TimeZone) entry.getValue()).getRawOffset() == rawOffset) + ids[count++] = (String) entry.getKey(); + } + return ids; + } + } + + String[] s = getAvailableIDs(); + int count = 0; + for (int i = 0; i < s.length; i++) + { + TimeZone t = getTimeZoneInternal(s[i]); + if (t == null || t.getRawOffset() != rawOffset) + s[i] = null; + else + count++; + } + String[] ids = new String[count]; + count = 0; + for (int i = 0; i < s.length; i++) + if (s[i] != null) + ids[count++] = s[i]; + + return ids; + } + + private static int getAvailableIDs(File d, String prefix, ArrayList list) + { + String[] files = d.list(); + int count = files.length; + boolean top = prefix.length() == 0; + list.add (files); + for (int i = 0; i < files.length; i++) + { + if (top + && (files[i].equals("posix") + || files[i].equals("right") + || files[i].endsWith(".tab") + || aliases0.get(files[i]) != null)) + { + files[i] = null; + count--; + continue; + } + + File f = new File(d, files[i]); + if (f.isDirectory()) + { + count += getAvailableIDs(f, prefix + files[i] + + File.separatorChar, list) - 1; + files[i] = null; + } + else + files[i] = prefix + files[i]; + } + return count; + } + + /** + * Gets all available IDs. + * @return An array of all supported IDs. + */ + /*public static String[] getAvailableIDs() + { + synchronized (TimeZone.class) + { + HashMap h = timezones(); + if (zoneinfo_dir == null) + return (String[]) h.keySet().toArray(new String[h.size()]); + + if (availableIDs != null) + { + String[] ids = new String[availableIDs.length]; + for (int i = 0; i < availableIDs.length; i++) + ids[i] = availableIDs[i]; + return ids; + } + + File d = new File(zoneinfo_dir); + ArrayList list = new ArrayList(30); + int count = getAvailableIDs(d, "", list) + aliases0.size(); + availableIDs = new String[count]; + String[] ids = new String[count]; + + count = 0; + for (int i = 0; i < list.size(); i++) + { + String[] s = (String[]) list.get(i); + for (int j = 0; j < s.length; j++) + if (s[j] != null) + { + availableIDs[count] = s[j]; + ids[count++] = s[j]; + } + } + + Iterator iter = aliases0.entrySet().iterator(); + while (iter.hasNext()) + { + Map.Entry entry = (Map.Entry) iter.next(); + availableIDs[count] = (String) entry.getKey(); + ids[count++] = (String) entry.getKey(); + } + + return ids; + } + }*/ + + /** + * Returns the time zone under which the host is running. This + * can be changed with setDefault. + * + * @return A clone of the current default time zone for this host. + * @see #setDefault + */ + public static TimeZone getDefault() + { + return (TimeZone) defaultZone().clone(); + } + + public static void setDefault(TimeZone zone) + { + // Hmmmm. No Security checks? + defaultZone0 = zone; + } + + /** + * Test if the other time zone uses the same rule and only + * possibly differs in ID. This implementation for this particular + * class will return true if the raw offsets are identical. Subclasses + * should override this method if they use daylight savings. + * @return true if this zone has the same raw offset + */ + public boolean hasSameRules(TimeZone other) + { + return other.getRawOffset() == getRawOffset(); + } + + /** + * Returns a clone of this object. I can't imagine, why this is + * useful for a time zone. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (/*CloneNotSupported*/Exception ex) + { + return null; + } + } +}