Set of JDK classes needed to run javac jdk7-b147
authorJaroslav Tulach <jtulach@netbeans.org>
Thu, 03 Oct 2013 15:40:35 +0200
branchjdk7-b147
changeset 1334588d5bf7a560
parent 1318 1af7f8903b62
child 1335 f194f314cac0
child 1348 bca65655b36b
Set of JDK classes needed to run javac
rt/emul/compact/src/main/java/java/io/BufferedInputStream.java
rt/emul/compact/src/main/java/java/io/FileDescriptor.java
rt/emul/compact/src/main/java/java/io/FileInputStream.java
rt/emul/compact/src/main/java/java/io/FileOutputStream.java
rt/emul/compact/src/main/java/java/io/FileReader.java
rt/emul/compact/src/main/java/java/io/FileWriter.java
rt/emul/compact/src/main/java/java/io/LineNumberInputStream.java
rt/emul/compact/src/main/java/java/io/LineNumberReader.java
rt/emul/compact/src/main/java/java/io/SyncFailedException.java
rt/emul/compact/src/main/java/java/nio/charset/Charset.java
rt/emul/compact/src/main/java/java/nio/charset/CharsetDecoder.java
rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java
rt/emul/compact/src/main/java/java/nio/charset/IllegalCharsetNameException.java
rt/emul/compact/src/main/java/java/nio/charset/UnsupportedCharsetException.java
rt/emul/compact/src/main/java/java/security/AccessController.java
rt/emul/compact/src/main/java/java/security/PrivilegedAction.java
rt/emul/compact/src/main/java/java/security/PrivilegedActionException.java
rt/emul/compact/src/main/java/java/security/PrivilegedExceptionAction.java
rt/emul/compact/src/main/java/java/text/Annotation.java
rt/emul/compact/src/main/java/java/text/AttributedCharacterIterator.java
rt/emul/compact/src/main/java/java/text/AttributedString.java
rt/emul/compact/src/main/java/java/text/CalendarBuilder.java
rt/emul/compact/src/main/java/java/text/CharacterIterator.java
rt/emul/compact/src/main/java/java/text/CharacterIteratorFieldDelegate.java
rt/emul/compact/src/main/java/java/text/ChoiceFormat.java
rt/emul/compact/src/main/java/java/text/DateFormat.java
rt/emul/compact/src/main/java/java/text/DateFormatSymbols.java
rt/emul/compact/src/main/java/java/text/DecimalFormat.java
rt/emul/compact/src/main/java/java/text/DecimalFormatSymbols.java
rt/emul/compact/src/main/java/java/text/DigitList.java
rt/emul/compact/src/main/java/java/text/DontCareFieldPosition.java
rt/emul/compact/src/main/java/java/text/FieldPosition.java
rt/emul/compact/src/main/java/java/text/Format.java
rt/emul/compact/src/main/java/java/text/MessageFormat.java
rt/emul/compact/src/main/java/java/text/NumberFormat.java
rt/emul/compact/src/main/java/java/text/ParseException.java
rt/emul/compact/src/main/java/java/text/ParsePosition.java
rt/emul/compact/src/main/java/java/text/SimpleDateFormat.java
rt/emul/compact/src/main/java/java/util/Calendar.java
rt/emul/compact/src/main/java/java/util/Currency.java
rt/emul/compact/src/main/java/java/util/CurrencyData.properties
rt/emul/compact/src/main/java/java/util/Date.java
rt/emul/compact/src/main/java/java/util/MissingResourceException.java
rt/emul/compact/src/main/java/java/util/Properties.java
rt/emul/compact/src/main/java/java/util/PropertyResourceBundle.java
rt/emul/compact/src/main/java/java/util/ResourceBundle.java
rt/emul/compact/src/main/java/java/util/SimpleTimeZone.java
rt/emul/compact/src/main/java/java/util/TimeZone.java
rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java
rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentMap.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java
rt/emul/compact/src/main/java/java/util/concurrent/atomic/package-info.java
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/rt/emul/compact/src/main/java/java/io/BufferedInputStream.java	Thu Oct 03 15:40:35 2013 +0200
     1.3 @@ -0,0 +1,478 @@
     1.4 +/*
     1.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.  Oracle designates this
    1.11 + * particular file as subject to the "Classpath" exception as provided
    1.12 + * by Oracle in the LICENSE file that accompanied this code.
    1.13 + *
    1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.17 + * version 2 for more details (a copy is included in the LICENSE file that
    1.18 + * accompanied this code).
    1.19 + *
    1.20 + * You should have received a copy of the GNU General Public License version
    1.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.23 + *
    1.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.25 + * or visit www.oracle.com if you need additional information or have any
    1.26 + * questions.
    1.27 + */
    1.28 +
    1.29 +package java.io;
    1.30 +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
    1.31 +
    1.32 +/**
    1.33 + * A <code>BufferedInputStream</code> adds
    1.34 + * functionality to another input stream-namely,
    1.35 + * the ability to buffer the input and to
    1.36 + * support the <code>mark</code> and <code>reset</code>
    1.37 + * methods. When  the <code>BufferedInputStream</code>
    1.38 + * is created, an internal buffer array is
    1.39 + * created. As bytes  from the stream are read
    1.40 + * or skipped, the internal buffer is refilled
    1.41 + * as necessary  from the contained input stream,
    1.42 + * many bytes at a time. The <code>mark</code>
    1.43 + * operation  remembers a point in the input
    1.44 + * stream and the <code>reset</code> operation
    1.45 + * causes all the  bytes read since the most
    1.46 + * recent <code>mark</code> operation to be
    1.47 + * reread before new bytes are  taken from
    1.48 + * the contained input stream.
    1.49 + *
    1.50 + * @author  Arthur van Hoff
    1.51 + * @since   JDK1.0
    1.52 + */
    1.53 +public
    1.54 +class BufferedInputStream extends FilterInputStream {
    1.55 +
    1.56 +    private static int defaultBufferSize = 8192;
    1.57 +
    1.58 +    /**
    1.59 +     * The internal buffer array where the data is stored. When necessary,
    1.60 +     * it may be replaced by another array of
    1.61 +     * a different size.
    1.62 +     */
    1.63 +    protected volatile byte buf[];
    1.64 +
    1.65 +    /**
    1.66 +     * Atomic updater to provide compareAndSet for buf. This is
    1.67 +     * necessary because closes can be asynchronous. We use nullness
    1.68 +     * of buf[] as primary indicator that this stream is closed. (The
    1.69 +     * "in" field is also nulled out on close.)
    1.70 +     */
    1.71 +    private static final
    1.72 +        AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =
    1.73 +        AtomicReferenceFieldUpdater.newUpdater
    1.74 +        (BufferedInputStream.class,  byte[].class, "buf");
    1.75 +
    1.76 +    /**
    1.77 +     * The index one greater than the index of the last valid byte in
    1.78 +     * the buffer.
    1.79 +     * This value is always
    1.80 +     * in the range <code>0</code> through <code>buf.length</code>;
    1.81 +     * elements <code>buf[0]</code>  through <code>buf[count-1]
    1.82 +     * </code>contain buffered input data obtained
    1.83 +     * from the underlying  input stream.
    1.84 +     */
    1.85 +    protected int count;
    1.86 +
    1.87 +    /**
    1.88 +     * The current position in the buffer. This is the index of the next
    1.89 +     * character to be read from the <code>buf</code> array.
    1.90 +     * <p>
    1.91 +     * This value is always in the range <code>0</code>
    1.92 +     * through <code>count</code>. If it is less
    1.93 +     * than <code>count</code>, then  <code>buf[pos]</code>
    1.94 +     * is the next byte to be supplied as input;
    1.95 +     * if it is equal to <code>count</code>, then
    1.96 +     * the  next <code>read</code> or <code>skip</code>
    1.97 +     * operation will require more bytes to be
    1.98 +     * read from the contained  input stream.
    1.99 +     *
   1.100 +     * @see     java.io.BufferedInputStream#buf
   1.101 +     */
   1.102 +    protected int pos;
   1.103 +
   1.104 +    /**
   1.105 +     * The value of the <code>pos</code> field at the time the last
   1.106 +     * <code>mark</code> method was called.
   1.107 +     * <p>
   1.108 +     * This value is always
   1.109 +     * in the range <code>-1</code> through <code>pos</code>.
   1.110 +     * If there is no marked position in  the input
   1.111 +     * stream, this field is <code>-1</code>. If
   1.112 +     * there is a marked position in the input
   1.113 +     * stream,  then <code>buf[markpos]</code>
   1.114 +     * is the first byte to be supplied as input
   1.115 +     * after a <code>reset</code> operation. If
   1.116 +     * <code>markpos</code> is not <code>-1</code>,
   1.117 +     * then all bytes from positions <code>buf[markpos]</code>
   1.118 +     * through  <code>buf[pos-1]</code> must remain
   1.119 +     * in the buffer array (though they may be
   1.120 +     * moved to  another place in the buffer array,
   1.121 +     * with suitable adjustments to the values
   1.122 +     * of <code>count</code>,  <code>pos</code>,
   1.123 +     * and <code>markpos</code>); they may not
   1.124 +     * be discarded unless and until the difference
   1.125 +     * between <code>pos</code> and <code>markpos</code>
   1.126 +     * exceeds <code>marklimit</code>.
   1.127 +     *
   1.128 +     * @see     java.io.BufferedInputStream#mark(int)
   1.129 +     * @see     java.io.BufferedInputStream#pos
   1.130 +     */
   1.131 +    protected int markpos = -1;
   1.132 +
   1.133 +    /**
   1.134 +     * The maximum read ahead allowed after a call to the
   1.135 +     * <code>mark</code> method before subsequent calls to the
   1.136 +     * <code>reset</code> method fail.
   1.137 +     * Whenever the difference between <code>pos</code>
   1.138 +     * and <code>markpos</code> exceeds <code>marklimit</code>,
   1.139 +     * then the  mark may be dropped by setting
   1.140 +     * <code>markpos</code> to <code>-1</code>.
   1.141 +     *
   1.142 +     * @see     java.io.BufferedInputStream#mark(int)
   1.143 +     * @see     java.io.BufferedInputStream#reset()
   1.144 +     */
   1.145 +    protected int marklimit;
   1.146 +
   1.147 +    /**
   1.148 +     * Check to make sure that underlying input stream has not been
   1.149 +     * nulled out due to close; if not return it;
   1.150 +     */
   1.151 +    private InputStream getInIfOpen() throws IOException {
   1.152 +        InputStream input = in;
   1.153 +        if (input == null)
   1.154 +            throw new IOException("Stream closed");
   1.155 +        return input;
   1.156 +    }
   1.157 +
   1.158 +    /**
   1.159 +     * Check to make sure that buffer has not been nulled out due to
   1.160 +     * close; if not return it;
   1.161 +     */
   1.162 +    private byte[] getBufIfOpen() throws IOException {
   1.163 +        byte[] buffer = buf;
   1.164 +        if (buffer == null)
   1.165 +            throw new IOException("Stream closed");
   1.166 +        return buffer;
   1.167 +    }
   1.168 +
   1.169 +    /**
   1.170 +     * Creates a <code>BufferedInputStream</code>
   1.171 +     * and saves its  argument, the input stream
   1.172 +     * <code>in</code>, for later use. An internal
   1.173 +     * buffer array is created and  stored in <code>buf</code>.
   1.174 +     *
   1.175 +     * @param   in   the underlying input stream.
   1.176 +     */
   1.177 +    public BufferedInputStream(InputStream in) {
   1.178 +        this(in, defaultBufferSize);
   1.179 +    }
   1.180 +
   1.181 +    /**
   1.182 +     * Creates a <code>BufferedInputStream</code>
   1.183 +     * with the specified buffer size,
   1.184 +     * and saves its  argument, the input stream
   1.185 +     * <code>in</code>, for later use.  An internal
   1.186 +     * buffer array of length  <code>size</code>
   1.187 +     * is created and stored in <code>buf</code>.
   1.188 +     *
   1.189 +     * @param   in     the underlying input stream.
   1.190 +     * @param   size   the buffer size.
   1.191 +     * @exception IllegalArgumentException if size <= 0.
   1.192 +     */
   1.193 +    public BufferedInputStream(InputStream in, int size) {
   1.194 +        super(in);
   1.195 +        if (size <= 0) {
   1.196 +            throw new IllegalArgumentException("Buffer size <= 0");
   1.197 +        }
   1.198 +        buf = new byte[size];
   1.199 +    }
   1.200 +
   1.201 +    /**
   1.202 +     * Fills the buffer with more data, taking into account
   1.203 +     * shuffling and other tricks for dealing with marks.
   1.204 +     * Assumes that it is being called by a synchronized method.
   1.205 +     * This method also assumes that all data has already been read in,
   1.206 +     * hence pos > count.
   1.207 +     */
   1.208 +    private void fill() throws IOException {
   1.209 +        byte[] buffer = getBufIfOpen();
   1.210 +        if (markpos < 0)
   1.211 +            pos = 0;            /* no mark: throw away the buffer */
   1.212 +        else if (pos >= buffer.length)  /* no room left in buffer */
   1.213 +            if (markpos > 0) {  /* can throw away early part of the buffer */
   1.214 +                int sz = pos - markpos;
   1.215 +                System.arraycopy(buffer, markpos, buffer, 0, sz);
   1.216 +                pos = sz;
   1.217 +                markpos = 0;
   1.218 +            } else if (buffer.length >= marklimit) {
   1.219 +                markpos = -1;   /* buffer got too big, invalidate mark */
   1.220 +                pos = 0;        /* drop buffer contents */
   1.221 +            } else {            /* grow buffer */
   1.222 +                int nsz = pos * 2;
   1.223 +                if (nsz > marklimit)
   1.224 +                    nsz = marklimit;
   1.225 +                byte nbuf[] = new byte[nsz];
   1.226 +                System.arraycopy(buffer, 0, nbuf, 0, pos);
   1.227 +                if (!bufUpdater.compareAndSet(this, buffer, nbuf)) {
   1.228 +                    // Can't replace buf if there was an async close.
   1.229 +                    // Note: This would need to be changed if fill()
   1.230 +                    // is ever made accessible to multiple threads.
   1.231 +                    // But for now, the only way CAS can fail is via close.
   1.232 +                    // assert buf == null;
   1.233 +                    throw new IOException("Stream closed");
   1.234 +                }
   1.235 +                buffer = nbuf;
   1.236 +            }
   1.237 +        count = pos;
   1.238 +        int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
   1.239 +        if (n > 0)
   1.240 +            count = n + pos;
   1.241 +    }
   1.242 +
   1.243 +    /**
   1.244 +     * See
   1.245 +     * the general contract of the <code>read</code>
   1.246 +     * method of <code>InputStream</code>.
   1.247 +     *
   1.248 +     * @return     the next byte of data, or <code>-1</code> if the end of the
   1.249 +     *             stream is reached.
   1.250 +     * @exception  IOException  if this input stream has been closed by
   1.251 +     *                          invoking its {@link #close()} method,
   1.252 +     *                          or an I/O error occurs.
   1.253 +     * @see        java.io.FilterInputStream#in
   1.254 +     */
   1.255 +    public synchronized int read() throws IOException {
   1.256 +        if (pos >= count) {
   1.257 +            fill();
   1.258 +            if (pos >= count)
   1.259 +                return -1;
   1.260 +        }
   1.261 +        return getBufIfOpen()[pos++] & 0xff;
   1.262 +    }
   1.263 +
   1.264 +    /**
   1.265 +     * Read characters into a portion of an array, reading from the underlying
   1.266 +     * stream at most once if necessary.
   1.267 +     */
   1.268 +    private int read1(byte[] b, int off, int len) throws IOException {
   1.269 +        int avail = count - pos;
   1.270 +        if (avail <= 0) {
   1.271 +            /* If the requested length is at least as large as the buffer, and
   1.272 +               if there is no mark/reset activity, do not bother to copy the
   1.273 +               bytes into the local buffer.  In this way buffered streams will
   1.274 +               cascade harmlessly. */
   1.275 +            if (len >= getBufIfOpen().length && markpos < 0) {
   1.276 +                return getInIfOpen().read(b, off, len);
   1.277 +            }
   1.278 +            fill();
   1.279 +            avail = count - pos;
   1.280 +            if (avail <= 0) return -1;
   1.281 +        }
   1.282 +        int cnt = (avail < len) ? avail : len;
   1.283 +        System.arraycopy(getBufIfOpen(), pos, b, off, cnt);
   1.284 +        pos += cnt;
   1.285 +        return cnt;
   1.286 +    }
   1.287 +
   1.288 +    /**
   1.289 +     * Reads bytes from this byte-input stream into the specified byte array,
   1.290 +     * starting at the given offset.
   1.291 +     *
   1.292 +     * <p> This method implements the general contract of the corresponding
   1.293 +     * <code>{@link InputStream#read(byte[], int, int) read}</code> method of
   1.294 +     * the <code>{@link InputStream}</code> class.  As an additional
   1.295 +     * convenience, it attempts to read as many bytes as possible by repeatedly
   1.296 +     * invoking the <code>read</code> method of the underlying stream.  This
   1.297 +     * iterated <code>read</code> continues until one of the following
   1.298 +     * conditions becomes true: <ul>
   1.299 +     *
   1.300 +     *   <li> The specified number of bytes have been read,
   1.301 +     *
   1.302 +     *   <li> The <code>read</code> method of the underlying stream returns
   1.303 +     *   <code>-1</code>, indicating end-of-file, or
   1.304 +     *
   1.305 +     *   <li> The <code>available</code> method of the underlying stream
   1.306 +     *   returns zero, indicating that further input requests would block.
   1.307 +     *
   1.308 +     * </ul> If the first <code>read</code> on the underlying stream returns
   1.309 +     * <code>-1</code> to indicate end-of-file then this method returns
   1.310 +     * <code>-1</code>.  Otherwise this method returns the number of bytes
   1.311 +     * actually read.
   1.312 +     *
   1.313 +     * <p> Subclasses of this class are encouraged, but not required, to
   1.314 +     * attempt to read as many bytes as possible in the same fashion.
   1.315 +     *
   1.316 +     * @param      b     destination buffer.
   1.317 +     * @param      off   offset at which to start storing bytes.
   1.318 +     * @param      len   maximum number of bytes to read.
   1.319 +     * @return     the number of bytes read, or <code>-1</code> if the end of
   1.320 +     *             the stream has been reached.
   1.321 +     * @exception  IOException  if this input stream has been closed by
   1.322 +     *                          invoking its {@link #close()} method,
   1.323 +     *                          or an I/O error occurs.
   1.324 +     */
   1.325 +    public synchronized int read(byte b[], int off, int len)
   1.326 +        throws IOException
   1.327 +    {
   1.328 +        getBufIfOpen(); // Check for closed stream
   1.329 +        if ((off | len | (off + len) | (b.length - (off + len))) < 0) {
   1.330 +            throw new IndexOutOfBoundsException();
   1.331 +        } else if (len == 0) {
   1.332 +            return 0;
   1.333 +        }
   1.334 +
   1.335 +        int n = 0;
   1.336 +        for (;;) {
   1.337 +            int nread = read1(b, off + n, len - n);
   1.338 +            if (nread <= 0)
   1.339 +                return (n == 0) ? nread : n;
   1.340 +            n += nread;
   1.341 +            if (n >= len)
   1.342 +                return n;
   1.343 +            // if not closed but no bytes available, return
   1.344 +            InputStream input = in;
   1.345 +            if (input != null && input.available() <= 0)
   1.346 +                return n;
   1.347 +        }
   1.348 +    }
   1.349 +
   1.350 +    /**
   1.351 +     * See the general contract of the <code>skip</code>
   1.352 +     * method of <code>InputStream</code>.
   1.353 +     *
   1.354 +     * @exception  IOException  if the stream does not support seek,
   1.355 +     *                          or if this input stream has been closed by
   1.356 +     *                          invoking its {@link #close()} method, or an
   1.357 +     *                          I/O error occurs.
   1.358 +     */
   1.359 +    public synchronized long skip(long n) throws IOException {
   1.360 +        getBufIfOpen(); // Check for closed stream
   1.361 +        if (n <= 0) {
   1.362 +            return 0;
   1.363 +        }
   1.364 +        long avail = count - pos;
   1.365 +
   1.366 +        if (avail <= 0) {
   1.367 +            // If no mark position set then don't keep in buffer
   1.368 +            if (markpos <0)
   1.369 +                return getInIfOpen().skip(n);
   1.370 +
   1.371 +            // Fill in buffer to save bytes for reset
   1.372 +            fill();
   1.373 +            avail = count - pos;
   1.374 +            if (avail <= 0)
   1.375 +                return 0;
   1.376 +        }
   1.377 +
   1.378 +        long skipped = (avail < n) ? avail : n;
   1.379 +        pos += skipped;
   1.380 +        return skipped;
   1.381 +    }
   1.382 +
   1.383 +    /**
   1.384 +     * Returns an estimate of the number of bytes that can be read (or
   1.385 +     * skipped over) from this input stream without blocking by the next
   1.386 +     * invocation of a method for this input stream. The next invocation might be
   1.387 +     * the same thread or another thread.  A single read or skip of this
   1.388 +     * many bytes will not block, but may read or skip fewer bytes.
   1.389 +     * <p>
   1.390 +     * This method returns the sum of the number of bytes remaining to be read in
   1.391 +     * the buffer (<code>count&nbsp;- pos</code>) and the result of calling the
   1.392 +     * {@link java.io.FilterInputStream#in in}.available().
   1.393 +     *
   1.394 +     * @return     an estimate of the number of bytes that can be read (or skipped
   1.395 +     *             over) from this input stream without blocking.
   1.396 +     * @exception  IOException  if this input stream has been closed by
   1.397 +     *                          invoking its {@link #close()} method,
   1.398 +     *                          or an I/O error occurs.
   1.399 +     */
   1.400 +    public synchronized int available() throws IOException {
   1.401 +        int n = count - pos;
   1.402 +        int avail = getInIfOpen().available();
   1.403 +        return n > (Integer.MAX_VALUE - avail)
   1.404 +                    ? Integer.MAX_VALUE
   1.405 +                    : n + avail;
   1.406 +    }
   1.407 +
   1.408 +    /**
   1.409 +     * See the general contract of the <code>mark</code>
   1.410 +     * method of <code>InputStream</code>.
   1.411 +     *
   1.412 +     * @param   readlimit   the maximum limit of bytes that can be read before
   1.413 +     *                      the mark position becomes invalid.
   1.414 +     * @see     java.io.BufferedInputStream#reset()
   1.415 +     */
   1.416 +    public synchronized void mark(int readlimit) {
   1.417 +        marklimit = readlimit;
   1.418 +        markpos = pos;
   1.419 +    }
   1.420 +
   1.421 +    /**
   1.422 +     * See the general contract of the <code>reset</code>
   1.423 +     * method of <code>InputStream</code>.
   1.424 +     * <p>
   1.425 +     * If <code>markpos</code> is <code>-1</code>
   1.426 +     * (no mark has been set or the mark has been
   1.427 +     * invalidated), an <code>IOException</code>
   1.428 +     * is thrown. Otherwise, <code>pos</code> is
   1.429 +     * set equal to <code>markpos</code>.
   1.430 +     *
   1.431 +     * @exception  IOException  if this stream has not been marked or,
   1.432 +     *                  if the mark has been invalidated, or the stream
   1.433 +     *                  has been closed by invoking its {@link #close()}
   1.434 +     *                  method, or an I/O error occurs.
   1.435 +     * @see        java.io.BufferedInputStream#mark(int)
   1.436 +     */
   1.437 +    public synchronized void reset() throws IOException {
   1.438 +        getBufIfOpen(); // Cause exception if closed
   1.439 +        if (markpos < 0)
   1.440 +            throw new IOException("Resetting to invalid mark");
   1.441 +        pos = markpos;
   1.442 +    }
   1.443 +
   1.444 +    /**
   1.445 +     * Tests if this input stream supports the <code>mark</code>
   1.446 +     * and <code>reset</code> methods. The <code>markSupported</code>
   1.447 +     * method of <code>BufferedInputStream</code> returns
   1.448 +     * <code>true</code>.
   1.449 +     *
   1.450 +     * @return  a <code>boolean</code> indicating if this stream type supports
   1.451 +     *          the <code>mark</code> and <code>reset</code> methods.
   1.452 +     * @see     java.io.InputStream#mark(int)
   1.453 +     * @see     java.io.InputStream#reset()
   1.454 +     */
   1.455 +    public boolean markSupported() {
   1.456 +        return true;
   1.457 +    }
   1.458 +
   1.459 +    /**
   1.460 +     * Closes this input stream and releases any system resources
   1.461 +     * associated with the stream.
   1.462 +     * Once the stream has been closed, further read(), available(), reset(),
   1.463 +     * or skip() invocations will throw an IOException.
   1.464 +     * Closing a previously closed stream has no effect.
   1.465 +     *
   1.466 +     * @exception  IOException  if an I/O error occurs.
   1.467 +     */
   1.468 +    public void close() throws IOException {
   1.469 +        byte[] buffer;
   1.470 +        while ( (buffer = buf) != null) {
   1.471 +            if (bufUpdater.compareAndSet(this, buffer, null)) {
   1.472 +                InputStream input = in;
   1.473 +                in = null;
   1.474 +                if (input != null)
   1.475 +                    input.close();
   1.476 +                return;
   1.477 +            }
   1.478 +            // Else retry in case a new buf was CASed in fill()
   1.479 +        }
   1.480 +    }
   1.481 +}
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/rt/emul/compact/src/main/java/java/io/FileDescriptor.java	Thu Oct 03 15:40:35 2013 +0200
     2.3 @@ -0,0 +1,176 @@
     2.4 +/*
     2.5 + * Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
     2.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
     2.7 + *
     2.8 + *
     2.9 + *
    2.10 + *
    2.11 + *
    2.12 + *
    2.13 + *
    2.14 + *
    2.15 + *
    2.16 + *
    2.17 + *
    2.18 + *
    2.19 + *
    2.20 + *
    2.21 + *
    2.22 + *
    2.23 + *
    2.24 + *
    2.25 + *
    2.26 + *
    2.27 + */
    2.28 +
    2.29 +package java.io;
    2.30 +
    2.31 +import java.util.concurrent.atomic.AtomicInteger;
    2.32 +
    2.33 +/**
    2.34 + * Instances of the file descriptor class serve as an opaque handle
    2.35 + * to the underlying machine-specific structure representing an open
    2.36 + * file, an open socket, or another source or sink of bytes. The
    2.37 + * main practical use for a file descriptor is to create a
    2.38 + * <code>FileInputStream</code> or <code>FileOutputStream</code> to
    2.39 + * contain it.
    2.40 + * <p>
    2.41 + * Applications should not create their own file descriptors.
    2.42 + *
    2.43 + * @author  Pavani Diwanji
    2.44 + * @see     java.io.FileInputStream
    2.45 + * @see     java.io.FileOutputStream
    2.46 + * @since   JDK1.0
    2.47 + */
    2.48 +public final class FileDescriptor {
    2.49 +
    2.50 +    private int fd;
    2.51 +
    2.52 +    /**
    2.53 +     * A counter for tracking the FIS/FOS/RAF instances that
    2.54 +     * use this FileDescriptor. The FIS/FOS.finalize() will not release
    2.55 +     * the FileDescriptor if it is still under user by a stream.
    2.56 +     */
    2.57 +    private AtomicInteger useCount;
    2.58 +
    2.59 +    /**
    2.60 +     * Constructs an (invalid) FileDescriptor
    2.61 +     * object.
    2.62 +     */
    2.63 +    public /**/ FileDescriptor() {
    2.64 +        fd = -1;
    2.65 +        useCount = new AtomicInteger();
    2.66 +    }
    2.67 +
    2.68 +    private /* */ FileDescriptor(int fd) {
    2.69 +        this.fd = fd;
    2.70 +        useCount = new AtomicInteger();
    2.71 +    }
    2.72 +
    2.73 +    /**
    2.74 +     * A handle to the standard input stream. Usually, this file
    2.75 +     * descriptor is not used directly, but rather via the input stream
    2.76 +     * known as <code>System.in</code>.
    2.77 +     *
    2.78 +     * @see     java.lang.System#in
    2.79 +     */
    2.80 +    public static final FileDescriptor in = new FileDescriptor(0);
    2.81 +
    2.82 +    /**
    2.83 +     * A handle to the standard output stream. Usually, this file
    2.84 +     * descriptor is not used directly, but rather via the output stream
    2.85 +     * known as <code>System.out</code>.
    2.86 +     * @see     java.lang.System#out
    2.87 +     */
    2.88 +    public static final FileDescriptor out = new FileDescriptor(1);
    2.89 +
    2.90 +    /**
    2.91 +     * A handle to the standard error stream. Usually, this file
    2.92 +     * descriptor is not used directly, but rather via the output stream
    2.93 +     * known as <code>System.err</code>.
    2.94 +     *
    2.95 +     * @see     java.lang.System#err
    2.96 +     */
    2.97 +    public static final FileDescriptor err = new FileDescriptor(2);
    2.98 +
    2.99 +    /**
   2.100 +     * Tests if this file descriptor object is valid.
   2.101 +     *
   2.102 +     * @return  <code>true</code> if the file descriptor object represents a
   2.103 +     *          valid, open file, socket, or other active I/O connection;
   2.104 +     *          <code>false</code> otherwise.
   2.105 +     */
   2.106 +    public boolean valid() {
   2.107 +        return fd != -1;
   2.108 +    }
   2.109 +
   2.110 +    /**
   2.111 +     * Force all system buffers to synchronize with the underlying
   2.112 +     * device.  This method returns after all modified data and
   2.113 +     * attributes of this FileDescriptor have been written to the
   2.114 +     * relevant device(s).  In particular, if this FileDescriptor
   2.115 +     * refers to a physical storage medium, such as a file in a file
   2.116 +     * system, sync will not return until all in-memory modified copies
   2.117 +     * of buffers associated with this FileDescriptor have been
   2.118 +     * written to the physical medium.
   2.119 +     *
   2.120 +     * sync is meant to be used by code that requires physical
   2.121 +     * storage (such as a file) to be in a known state  For
   2.122 +     * example, a class that provided a simple transaction facility
   2.123 +     * might use sync to ensure that all changes to a file caused
   2.124 +     * by a given transaction were recorded on a storage medium.
   2.125 +     *
   2.126 +     * sync only affects buffers downstream of this FileDescriptor.  If
   2.127 +     * any in-memory buffering is being done by the application (for
   2.128 +     * example, by a BufferedOutputStream object), those buffers must
   2.129 +     * be flushed into the FileDescriptor (for example, by invoking
   2.130 +     * OutputStream.flush) before that data will be affected by sync.
   2.131 +     *
   2.132 +     * @exception SyncFailedException
   2.133 +     *        Thrown when the buffers cannot be flushed,
   2.134 +     *        or because the system cannot guarantee that all the
   2.135 +     *        buffers have been synchronized with physical media.
   2.136 +     * @since     JDK1.1
   2.137 +     */
   2.138 +    public native void sync() throws SyncFailedException;
   2.139 +
   2.140 +    /* This routine initializes JNI field offsets for the class */
   2.141 +    private static native void initIDs();
   2.142 +
   2.143 +    static {
   2.144 +        initIDs();
   2.145 +    }
   2.146 +
   2.147 +    // Set up JavaIOFileDescriptorAccess in SharedSecrets
   2.148 +    static {
   2.149 +        sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
   2.150 +            new sun.misc.JavaIOFileDescriptorAccess() {
   2.151 +                public void set(FileDescriptor obj, int fd) {
   2.152 +                    obj.fd = fd;
   2.153 +                }
   2.154 +
   2.155 +                public int get(FileDescriptor obj) {
   2.156 +                    return obj.fd;
   2.157 +                }
   2.158 +
   2.159 +                public void setHandle(FileDescriptor obj, long handle) {
   2.160 +                    throw new UnsupportedOperationException();
   2.161 +                }
   2.162 +
   2.163 +                public long getHandle(FileDescriptor obj) {
   2.164 +                    throw new UnsupportedOperationException();
   2.165 +                }
   2.166 +            }
   2.167 +        );
   2.168 +    }
   2.169 +
   2.170 +    // package private methods used by FIS, FOS and RAF
   2.171 +
   2.172 +    int incrementAndGetUseCount() {
   2.173 +        return useCount.incrementAndGet();
   2.174 +    }
   2.175 +
   2.176 +    int decrementAndGetUseCount() {
   2.177 +        return useCount.decrementAndGet();
   2.178 +    }
   2.179 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/rt/emul/compact/src/main/java/java/io/FileInputStream.java	Thu Oct 03 15:40:35 2013 +0200
     3.3 @@ -0,0 +1,408 @@
     3.4 +/*
     3.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.  Oracle designates this
    3.11 + * particular file as subject to the "Classpath" exception as provided
    3.12 + * by Oracle in the LICENSE file that accompanied this code.
    3.13 + *
    3.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.17 + * version 2 for more details (a copy is included in the LICENSE file that
    3.18 + * accompanied this code).
    3.19 + *
    3.20 + * You should have received a copy of the GNU General Public License version
    3.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.23 + *
    3.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    3.25 + * or visit www.oracle.com if you need additional information or have any
    3.26 + * questions.
    3.27 + */
    3.28 +
    3.29 +package java.io;
    3.30 +
    3.31 +import java.nio.channels.FileChannel;
    3.32 +import sun.nio.ch.FileChannelImpl;
    3.33 +
    3.34 +
    3.35 +/**
    3.36 + * A <code>FileInputStream</code> obtains input bytes
    3.37 + * from a file in a file system. What files
    3.38 + * are  available depends on the host environment.
    3.39 + *
    3.40 + * <p><code>FileInputStream</code> is meant for reading streams of raw bytes
    3.41 + * such as image data. For reading streams of characters, consider using
    3.42 + * <code>FileReader</code>.
    3.43 + *
    3.44 + * @author  Arthur van Hoff
    3.45 + * @see     java.io.File
    3.46 + * @see     java.io.FileDescriptor
    3.47 + * @see     java.io.FileOutputStream
    3.48 + * @see     java.nio.file.Files#newInputStream
    3.49 + * @since   JDK1.0
    3.50 + */
    3.51 +public
    3.52 +class FileInputStream extends InputStream
    3.53 +{
    3.54 +    /* File Descriptor - handle to the open file */
    3.55 +    private final FileDescriptor fd;
    3.56 +
    3.57 +    private FileChannel channel = null;
    3.58 +
    3.59 +    private final Object closeLock = new Object();
    3.60 +    private volatile boolean closed = false;
    3.61 +
    3.62 +    private static final ThreadLocal<Boolean> runningFinalize =
    3.63 +        new ThreadLocal<>();
    3.64 +
    3.65 +    private static boolean isRunningFinalize() {
    3.66 +        Boolean val;
    3.67 +        if ((val = runningFinalize.get()) != null)
    3.68 +            return val.booleanValue();
    3.69 +        return false;
    3.70 +    }
    3.71 +
    3.72 +    /**
    3.73 +     * Creates a <code>FileInputStream</code> by
    3.74 +     * opening a connection to an actual file,
    3.75 +     * the file named by the path name <code>name</code>
    3.76 +     * in the file system.  A new <code>FileDescriptor</code>
    3.77 +     * object is created to represent this file
    3.78 +     * connection.
    3.79 +     * <p>
    3.80 +     * First, if there is a security
    3.81 +     * manager, its <code>checkRead</code> method
    3.82 +     * is called with the <code>name</code> argument
    3.83 +     * as its argument.
    3.84 +     * <p>
    3.85 +     * If the named file does not exist, is a directory rather than a regular
    3.86 +     * file, or for some other reason cannot be opened for reading then a
    3.87 +     * <code>FileNotFoundException</code> is thrown.
    3.88 +     *
    3.89 +     * @param      name   the system-dependent file name.
    3.90 +     * @exception  FileNotFoundException  if the file does not exist,
    3.91 +     *                   is a directory rather than a regular file,
    3.92 +     *                   or for some other reason cannot be opened for
    3.93 +     *                   reading.
    3.94 +     * @exception  SecurityException      if a security manager exists and its
    3.95 +     *               <code>checkRead</code> method denies read access
    3.96 +     *               to the file.
    3.97 +     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
    3.98 +     */
    3.99 +    public FileInputStream(String name) throws FileNotFoundException {
   3.100 +        this(name != null ? new File(name) : null);
   3.101 +    }
   3.102 +
   3.103 +    /**
   3.104 +     * Creates a <code>FileInputStream</code> by
   3.105 +     * opening a connection to an actual file,
   3.106 +     * the file named by the <code>File</code>
   3.107 +     * object <code>file</code> in the file system.
   3.108 +     * A new <code>FileDescriptor</code> object
   3.109 +     * is created to represent this file connection.
   3.110 +     * <p>
   3.111 +     * First, if there is a security manager,
   3.112 +     * its <code>checkRead</code> method  is called
   3.113 +     * with the path represented by the <code>file</code>
   3.114 +     * argument as its argument.
   3.115 +     * <p>
   3.116 +     * If the named file does not exist, is a directory rather than a regular
   3.117 +     * file, or for some other reason cannot be opened for reading then a
   3.118 +     * <code>FileNotFoundException</code> is thrown.
   3.119 +     *
   3.120 +     * @param      file   the file to be opened for reading.
   3.121 +     * @exception  FileNotFoundException  if the file does not exist,
   3.122 +     *                   is a directory rather than a regular file,
   3.123 +     *                   or for some other reason cannot be opened for
   3.124 +     *                   reading.
   3.125 +     * @exception  SecurityException      if a security manager exists and its
   3.126 +     *               <code>checkRead</code> method denies read access to the file.
   3.127 +     * @see        java.io.File#getPath()
   3.128 +     * @see        java.lang.SecurityManager#checkRead(java.lang.String)
   3.129 +     */
   3.130 +    public FileInputStream(File file) throws FileNotFoundException {
   3.131 +        String name = (file != null ? file.getPath() : null);
   3.132 +        SecurityManager security = System.getSecurityManager();
   3.133 +        if (security != null) {
   3.134 +            security.checkRead(name);
   3.135 +        }
   3.136 +        if (name == null) {
   3.137 +            throw new NullPointerException();
   3.138 +        }
   3.139 +        fd = new FileDescriptor();
   3.140 +        fd.incrementAndGetUseCount();
   3.141 +        open(name);
   3.142 +    }
   3.143 +
   3.144 +    /**
   3.145 +     * Creates a <code>FileInputStream</code> by using the file descriptor
   3.146 +     * <code>fdObj</code>, which represents an existing connection to an
   3.147 +     * actual file in the file system.
   3.148 +     * <p>
   3.149 +     * If there is a security manager, its <code>checkRead</code> method is
   3.150 +     * called with the file descriptor <code>fdObj</code> as its argument to
   3.151 +     * see if it's ok to read the file descriptor. If read access is denied
   3.152 +     * to the file descriptor a <code>SecurityException</code> is thrown.
   3.153 +     * <p>
   3.154 +     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
   3.155 +     * is thrown.
   3.156 +     * <p>
   3.157 +     * This constructor does not throw an exception if <code>fdObj</code>
   3.158 +     * is {@link java.io.FileDescriptor#valid() invalid}.
   3.159 +     * However, if the methods are invoked on the resulting stream to attempt
   3.160 +     * I/O on the stream, an <code>IOException</code> is thrown.
   3.161 +     *
   3.162 +     * @param      fdObj   the file descriptor to be opened for reading.
   3.163 +     * @throws     SecurityException      if a security manager exists and its
   3.164 +     *                 <code>checkRead</code> method denies read access to the
   3.165 +     *                 file descriptor.
   3.166 +     * @see        SecurityManager#checkRead(java.io.FileDescriptor)
   3.167 +     */
   3.168 +    public FileInputStream(FileDescriptor fdObj) {
   3.169 +        SecurityManager security = System.getSecurityManager();
   3.170 +        if (fdObj == null) {
   3.171 +            throw new NullPointerException();
   3.172 +        }
   3.173 +        if (security != null) {
   3.174 +            security.checkRead(fdObj);
   3.175 +        }
   3.176 +        fd = fdObj;
   3.177 +
   3.178 +        /*
   3.179 +         * FileDescriptor is being shared by streams.
   3.180 +         * Ensure that it's GC'ed only when all the streams/channels are done
   3.181 +         * using it.
   3.182 +         */
   3.183 +        fd.incrementAndGetUseCount();
   3.184 +    }
   3.185 +
   3.186 +    /**
   3.187 +     * Opens the specified file for reading.
   3.188 +     * @param name the name of the file
   3.189 +     */
   3.190 +    private native void open(String name) throws FileNotFoundException;
   3.191 +
   3.192 +    /**
   3.193 +     * Reads a byte of data from this input stream. This method blocks
   3.194 +     * if no input is yet available.
   3.195 +     *
   3.196 +     * @return     the next byte of data, or <code>-1</code> if the end of the
   3.197 +     *             file is reached.
   3.198 +     * @exception  IOException  if an I/O error occurs.
   3.199 +     */
   3.200 +    public native int read() throws IOException;
   3.201 +
   3.202 +    /**
   3.203 +     * Reads a subarray as a sequence of bytes.
   3.204 +     * @param b the data to be written
   3.205 +     * @param off the start offset in the data
   3.206 +     * @param len the number of bytes that are written
   3.207 +     * @exception IOException If an I/O error has occurred.
   3.208 +     */
   3.209 +    private native int readBytes(byte b[], int off, int len) throws IOException;
   3.210 +
   3.211 +    /**
   3.212 +     * Reads up to <code>b.length</code> bytes of data from this input
   3.213 +     * stream into an array of bytes. This method blocks until some input
   3.214 +     * is available.
   3.215 +     *
   3.216 +     * @param      b   the buffer into which the data is read.
   3.217 +     * @return     the total number of bytes read into the buffer, or
   3.218 +     *             <code>-1</code> if there is no more data because the end of
   3.219 +     *             the file has been reached.
   3.220 +     * @exception  IOException  if an I/O error occurs.
   3.221 +     */
   3.222 +    public int read(byte b[]) throws IOException {
   3.223 +        return readBytes(b, 0, b.length);
   3.224 +    }
   3.225 +
   3.226 +    /**
   3.227 +     * Reads up to <code>len</code> bytes of data from this input stream
   3.228 +     * into an array of bytes. If <code>len</code> is not zero, the method
   3.229 +     * blocks until some input is available; otherwise, no
   3.230 +     * bytes are read and <code>0</code> is returned.
   3.231 +     *
   3.232 +     * @param      b     the buffer into which the data is read.
   3.233 +     * @param      off   the start offset in the destination array <code>b</code>
   3.234 +     * @param      len   the maximum number of bytes read.
   3.235 +     * @return     the total number of bytes read into the buffer, or
   3.236 +     *             <code>-1</code> if there is no more data because the end of
   3.237 +     *             the file has been reached.
   3.238 +     * @exception  NullPointerException If <code>b</code> is <code>null</code>.
   3.239 +     * @exception  IndexOutOfBoundsException If <code>off</code> is negative,
   3.240 +     * <code>len</code> is negative, or <code>len</code> is greater than
   3.241 +     * <code>b.length - off</code>
   3.242 +     * @exception  IOException  if an I/O error occurs.
   3.243 +     */
   3.244 +    public int read(byte b[], int off, int len) throws IOException {
   3.245 +        return readBytes(b, off, len);
   3.246 +    }
   3.247 +
   3.248 +    /**
   3.249 +     * Skips over and discards <code>n</code> bytes of data from the
   3.250 +     * input stream.
   3.251 +     *
   3.252 +     * <p>The <code>skip</code> method may, for a variety of
   3.253 +     * reasons, end up skipping over some smaller number of bytes,
   3.254 +     * possibly <code>0</code>. If <code>n</code> is negative, an
   3.255 +     * <code>IOException</code> is thrown, even though the <code>skip</code>
   3.256 +     * method of the {@link InputStream} superclass does nothing in this case.
   3.257 +     * The actual number of bytes skipped is returned.
   3.258 +     *
   3.259 +     * <p>This method may skip more bytes than are remaining in the backing
   3.260 +     * file. This produces no exception and the number of bytes skipped
   3.261 +     * may include some number of bytes that were beyond the EOF of the
   3.262 +     * backing file. Attempting to read from the stream after skipping past
   3.263 +     * the end will result in -1 indicating the end of the file.
   3.264 +     *
   3.265 +     * @param      n   the number of bytes to be skipped.
   3.266 +     * @return     the actual number of bytes skipped.
   3.267 +     * @exception  IOException  if n is negative, if the stream does not
   3.268 +     *             support seek, or if an I/O error occurs.
   3.269 +     */
   3.270 +    public native long skip(long n) throws IOException;
   3.271 +
   3.272 +    /**
   3.273 +     * Returns an estimate of the number of remaining bytes that can be read (or
   3.274 +     * skipped over) from this input stream without blocking by the next
   3.275 +     * invocation of a method for this input stream. The next invocation might be
   3.276 +     * the same thread or another thread.  A single read or skip of this
   3.277 +     * many bytes will not block, but may read or skip fewer bytes.
   3.278 +     *
   3.279 +     * <p> In some cases, a non-blocking read (or skip) may appear to be
   3.280 +     * blocked when it is merely slow, for example when reading large
   3.281 +     * files over slow networks.
   3.282 +     *
   3.283 +     * @return     an estimate of the number of remaining bytes that can be read
   3.284 +     *             (or skipped over) from this input stream without blocking.
   3.285 +     * @exception  IOException  if this file input stream has been closed by calling
   3.286 +     *             {@code close} or an I/O error occurs.
   3.287 +     */
   3.288 +    public native int available() throws IOException;
   3.289 +
   3.290 +    /**
   3.291 +     * Closes this file input stream and releases any system resources
   3.292 +     * associated with the stream.
   3.293 +     *
   3.294 +     * <p> If this stream has an associated channel then the channel is closed
   3.295 +     * as well.
   3.296 +     *
   3.297 +     * @exception  IOException  if an I/O error occurs.
   3.298 +     *
   3.299 +     * @revised 1.4
   3.300 +     * @spec JSR-51
   3.301 +     */
   3.302 +    public void close() throws IOException {
   3.303 +        synchronized (closeLock) {
   3.304 +            if (closed) {
   3.305 +                return;
   3.306 +            }
   3.307 +            closed = true;
   3.308 +        }
   3.309 +        if (channel != null) {
   3.310 +            /*
   3.311 +             * Decrement the FD use count associated with the channel
   3.312 +             * The use count is incremented whenever a new channel
   3.313 +             * is obtained from this stream.
   3.314 +             */
   3.315 +           fd.decrementAndGetUseCount();
   3.316 +           channel.close();
   3.317 +        }
   3.318 +
   3.319 +        /*
   3.320 +         * Decrement the FD use count associated with this stream
   3.321 +         */
   3.322 +        int useCount = fd.decrementAndGetUseCount();
   3.323 +
   3.324 +        /*
   3.325 +         * If FileDescriptor is still in use by another stream, the finalizer
   3.326 +         * will not close it.
   3.327 +         */
   3.328 +        if ((useCount <= 0) || !isRunningFinalize()) {
   3.329 +            close0();
   3.330 +        }
   3.331 +    }
   3.332 +
   3.333 +    /**
   3.334 +     * Returns the <code>FileDescriptor</code>
   3.335 +     * object  that represents the connection to
   3.336 +     * the actual file in the file system being
   3.337 +     * used by this <code>FileInputStream</code>.
   3.338 +     *
   3.339 +     * @return     the file descriptor object associated with this stream.
   3.340 +     * @exception  IOException  if an I/O error occurs.
   3.341 +     * @see        java.io.FileDescriptor
   3.342 +     */
   3.343 +    public final FileDescriptor getFD() throws IOException {
   3.344 +        if (fd != null) return fd;
   3.345 +        throw new IOException();
   3.346 +    }
   3.347 +
   3.348 +    /**
   3.349 +     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
   3.350 +     * object associated with this file input stream.
   3.351 +     *
   3.352 +     * <p> The initial {@link java.nio.channels.FileChannel#position()
   3.353 +     * </code>position<code>} of the returned channel will be equal to the
   3.354 +     * number of bytes read from the file so far.  Reading bytes from this
   3.355 +     * stream will increment the channel's position.  Changing the channel's
   3.356 +     * position, either explicitly or by reading, will change this stream's
   3.357 +     * file position.
   3.358 +     *
   3.359 +     * @return  the file channel associated with this file input stream
   3.360 +     *
   3.361 +     * @since 1.4
   3.362 +     * @spec JSR-51
   3.363 +     */
   3.364 +    public FileChannel getChannel() {
   3.365 +        synchronized (this) {
   3.366 +            if (channel == null) {
   3.367 +                channel = FileChannelImpl.open(fd, true, false, this);
   3.368 +
   3.369 +                /*
   3.370 +                 * Increment fd's use count. Invoking the channel's close()
   3.371 +                 * method will result in decrementing the use count set for
   3.372 +                 * the channel.
   3.373 +                 */
   3.374 +                fd.incrementAndGetUseCount();
   3.375 +            }
   3.376 +            return channel;
   3.377 +        }
   3.378 +    }
   3.379 +
   3.380 +    private static native void initIDs();
   3.381 +
   3.382 +    private native void close0() throws IOException;
   3.383 +
   3.384 +    static {
   3.385 +        initIDs();
   3.386 +    }
   3.387 +
   3.388 +    /**
   3.389 +     * Ensures that the <code>close</code> method of this file input stream is
   3.390 +     * called when there are no more references to it.
   3.391 +     *
   3.392 +     * @exception  IOException  if an I/O error occurs.
   3.393 +     * @see        java.io.FileInputStream#close()
   3.394 +     */
   3.395 +    protected void finalize() throws IOException {
   3.396 +        if ((fd != null) &&  (fd != FileDescriptor.in)) {
   3.397 +
   3.398 +            /*
   3.399 +             * Finalizer should not release the FileDescriptor if another
   3.400 +             * stream is still using it. If the user directly invokes
   3.401 +             * close() then the FileDescriptor is also released.
   3.402 +             */
   3.403 +            runningFinalize.set(Boolean.TRUE);
   3.404 +            try {
   3.405 +                close();
   3.406 +            } finally {
   3.407 +                runningFinalize.set(Boolean.FALSE);
   3.408 +            }
   3.409 +        }
   3.410 +    }
   3.411 +}
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/rt/emul/compact/src/main/java/java/io/FileOutputStream.java	Thu Oct 03 15:40:35 2013 +0200
     4.3 @@ -0,0 +1,451 @@
     4.4 +/*
     4.5 + * Copyright (c) 1994, 2011, Oracle and/or its affiliates. All rights reserved.
     4.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4.7 + *
     4.8 + * This code is free software; you can redistribute it and/or modify it
     4.9 + * under the terms of the GNU General Public License version 2 only, as
    4.10 + * published by the Free Software Foundation.  Oracle designates this
    4.11 + * particular file as subject to the "Classpath" exception as provided
    4.12 + * by Oracle in the LICENSE file that accompanied this code.
    4.13 + *
    4.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    4.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    4.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    4.17 + * version 2 for more details (a copy is included in the LICENSE file that
    4.18 + * accompanied this code).
    4.19 + *
    4.20 + * You should have received a copy of the GNU General Public License version
    4.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    4.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    4.23 + *
    4.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    4.25 + * or visit www.oracle.com if you need additional information or have any
    4.26 + * questions.
    4.27 + */
    4.28 +
    4.29 +package java.io;
    4.30 +
    4.31 +import java.nio.channels.FileChannel;
    4.32 +import sun.nio.ch.FileChannelImpl;
    4.33 +
    4.34 +
    4.35 +/**
    4.36 + * A file output stream is an output stream for writing data to a
    4.37 + * <code>File</code> or to a <code>FileDescriptor</code>. Whether or not
    4.38 + * a file is available or may be created depends upon the underlying
    4.39 + * platform.  Some platforms, in particular, allow a file to be opened
    4.40 + * for writing by only one <tt>FileOutputStream</tt> (or other
    4.41 + * file-writing object) at a time.  In such situations the constructors in
    4.42 + * this class will fail if the file involved is already open.
    4.43 + *
    4.44 + * <p><code>FileOutputStream</code> is meant for writing streams of raw bytes
    4.45 + * such as image data. For writing streams of characters, consider using
    4.46 + * <code>FileWriter</code>.
    4.47 + *
    4.48 + * @author  Arthur van Hoff
    4.49 + * @see     java.io.File
    4.50 + * @see     java.io.FileDescriptor
    4.51 + * @see     java.io.FileInputStream
    4.52 + * @see     java.nio.file.Files#newOutputStream
    4.53 + * @since   JDK1.0
    4.54 + */
    4.55 +public
    4.56 +class FileOutputStream extends OutputStream
    4.57 +{
    4.58 +    /**
    4.59 +     * The system dependent file descriptor.
    4.60 +     */
    4.61 +    private final FileDescriptor fd;
    4.62 +
    4.63 +    /**
    4.64 +     * True if the file is opened for append.
    4.65 +     */
    4.66 +    private final boolean append;
    4.67 +
    4.68 +    /**
    4.69 +     * The associated channel, initalized lazily.
    4.70 +     */
    4.71 +    private FileChannel channel;
    4.72 +
    4.73 +    private final Object closeLock = new Object();
    4.74 +    private volatile boolean closed = false;
    4.75 +    private static final ThreadLocal<Boolean> runningFinalize =
    4.76 +        new ThreadLocal<>();
    4.77 +
    4.78 +    private static boolean isRunningFinalize() {
    4.79 +        Boolean val;
    4.80 +        if ((val = runningFinalize.get()) != null)
    4.81 +            return val.booleanValue();
    4.82 +        return false;
    4.83 +    }
    4.84 +
    4.85 +    /**
    4.86 +     * Creates a file output stream to write to the file with the
    4.87 +     * specified name. A new <code>FileDescriptor</code> object is
    4.88 +     * created to represent this file connection.
    4.89 +     * <p>
    4.90 +     * First, if there is a security manager, its <code>checkWrite</code>
    4.91 +     * method is called with <code>name</code> as its argument.
    4.92 +     * <p>
    4.93 +     * If the file exists but is a directory rather than a regular file, does
    4.94 +     * not exist but cannot be created, or cannot be opened for any other
    4.95 +     * reason then a <code>FileNotFoundException</code> is thrown.
    4.96 +     *
    4.97 +     * @param      name   the system-dependent filename
    4.98 +     * @exception  FileNotFoundException  if the file exists but is a directory
    4.99 +     *                   rather than a regular file, does not exist but cannot
   4.100 +     *                   be created, or cannot be opened for any other reason
   4.101 +     * @exception  SecurityException  if a security manager exists and its
   4.102 +     *               <code>checkWrite</code> method denies write access
   4.103 +     *               to the file.
   4.104 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   4.105 +     */
   4.106 +    public FileOutputStream(String name) throws FileNotFoundException {
   4.107 +        this(name != null ? new File(name) : null, false);
   4.108 +    }
   4.109 +
   4.110 +    /**
   4.111 +     * Creates a file output stream to write to the file with the specified
   4.112 +     * name.  If the second argument is <code>true</code>, then
   4.113 +     * bytes will be written to the end of the file rather than the beginning.
   4.114 +     * A new <code>FileDescriptor</code> object is created to represent this
   4.115 +     * file connection.
   4.116 +     * <p>
   4.117 +     * First, if there is a security manager, its <code>checkWrite</code>
   4.118 +     * method is called with <code>name</code> as its argument.
   4.119 +     * <p>
   4.120 +     * If the file exists but is a directory rather than a regular file, does
   4.121 +     * not exist but cannot be created, or cannot be opened for any other
   4.122 +     * reason then a <code>FileNotFoundException</code> is thrown.
   4.123 +     *
   4.124 +     * @param     name        the system-dependent file name
   4.125 +     * @param     append      if <code>true</code>, then bytes will be written
   4.126 +     *                   to the end of the file rather than the beginning
   4.127 +     * @exception  FileNotFoundException  if the file exists but is a directory
   4.128 +     *                   rather than a regular file, does not exist but cannot
   4.129 +     *                   be created, or cannot be opened for any other reason.
   4.130 +     * @exception  SecurityException  if a security manager exists and its
   4.131 +     *               <code>checkWrite</code> method denies write access
   4.132 +     *               to the file.
   4.133 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   4.134 +     * @since     JDK1.1
   4.135 +     */
   4.136 +    public FileOutputStream(String name, boolean append)
   4.137 +        throws FileNotFoundException
   4.138 +    {
   4.139 +        this(name != null ? new File(name) : null, append);
   4.140 +    }
   4.141 +
   4.142 +    /**
   4.143 +     * Creates a file output stream to write to the file represented by
   4.144 +     * the specified <code>File</code> object. A new
   4.145 +     * <code>FileDescriptor</code> object is created to represent this
   4.146 +     * file connection.
   4.147 +     * <p>
   4.148 +     * First, if there is a security manager, its <code>checkWrite</code>
   4.149 +     * method is called with the path represented by the <code>file</code>
   4.150 +     * argument as its argument.
   4.151 +     * <p>
   4.152 +     * If the file exists but is a directory rather than a regular file, does
   4.153 +     * not exist but cannot be created, or cannot be opened for any other
   4.154 +     * reason then a <code>FileNotFoundException</code> is thrown.
   4.155 +     *
   4.156 +     * @param      file               the file to be opened for writing.
   4.157 +     * @exception  FileNotFoundException  if the file exists but is a directory
   4.158 +     *                   rather than a regular file, does not exist but cannot
   4.159 +     *                   be created, or cannot be opened for any other reason
   4.160 +     * @exception  SecurityException  if a security manager exists and its
   4.161 +     *               <code>checkWrite</code> method denies write access
   4.162 +     *               to the file.
   4.163 +     * @see        java.io.File#getPath()
   4.164 +     * @see        java.lang.SecurityException
   4.165 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   4.166 +     */
   4.167 +    public FileOutputStream(File file) throws FileNotFoundException {
   4.168 +        this(file, false);
   4.169 +    }
   4.170 +
   4.171 +    /**
   4.172 +     * Creates a file output stream to write to the file represented by
   4.173 +     * the specified <code>File</code> object. If the second argument is
   4.174 +     * <code>true</code>, then bytes will be written to the end of the file
   4.175 +     * rather than the beginning. A new <code>FileDescriptor</code> object is
   4.176 +     * created to represent this file connection.
   4.177 +     * <p>
   4.178 +     * First, if there is a security manager, its <code>checkWrite</code>
   4.179 +     * method is called with the path represented by the <code>file</code>
   4.180 +     * argument as its argument.
   4.181 +     * <p>
   4.182 +     * If the file exists but is a directory rather than a regular file, does
   4.183 +     * not exist but cannot be created, or cannot be opened for any other
   4.184 +     * reason then a <code>FileNotFoundException</code> is thrown.
   4.185 +     *
   4.186 +     * @param      file               the file to be opened for writing.
   4.187 +     * @param     append      if <code>true</code>, then bytes will be written
   4.188 +     *                   to the end of the file rather than the beginning
   4.189 +     * @exception  FileNotFoundException  if the file exists but is a directory
   4.190 +     *                   rather than a regular file, does not exist but cannot
   4.191 +     *                   be created, or cannot be opened for any other reason
   4.192 +     * @exception  SecurityException  if a security manager exists and its
   4.193 +     *               <code>checkWrite</code> method denies write access
   4.194 +     *               to the file.
   4.195 +     * @see        java.io.File#getPath()
   4.196 +     * @see        java.lang.SecurityException
   4.197 +     * @see        java.lang.SecurityManager#checkWrite(java.lang.String)
   4.198 +     * @since 1.4
   4.199 +     */
   4.200 +    public FileOutputStream(File file, boolean append)
   4.201 +        throws FileNotFoundException
   4.202 +    {
   4.203 +        String name = (file != null ? file.getPath() : null);
   4.204 +        SecurityManager security = System.getSecurityManager();
   4.205 +        if (security != null) {
   4.206 +            security.checkWrite(name);
   4.207 +        }
   4.208 +        if (name == null) {
   4.209 +            throw new NullPointerException();
   4.210 +        }
   4.211 +        this.fd = new FileDescriptor();
   4.212 +        this.append = append;
   4.213 +
   4.214 +        fd.incrementAndGetUseCount();
   4.215 +        open(name, append);
   4.216 +    }
   4.217 +
   4.218 +    /**
   4.219 +     * Creates a file output stream to write to the specified file
   4.220 +     * descriptor, which represents an existing connection to an actual
   4.221 +     * file in the file system.
   4.222 +     * <p>
   4.223 +     * First, if there is a security manager, its <code>checkWrite</code>
   4.224 +     * method is called with the file descriptor <code>fdObj</code>
   4.225 +     * argument as its argument.
   4.226 +     * <p>
   4.227 +     * If <code>fdObj</code> is null then a <code>NullPointerException</code>
   4.228 +     * is thrown.
   4.229 +     * <p>
   4.230 +     * This constructor does not throw an exception if <code>fdObj</code>
   4.231 +     * is {@link java.io.FileDescriptor#valid() invalid}.
   4.232 +     * However, if the methods are invoked on the resulting stream to attempt
   4.233 +     * I/O on the stream, an <code>IOException</code> is thrown.
   4.234 +     *
   4.235 +     * @param      fdObj   the file descriptor to be opened for writing
   4.236 +     * @exception  SecurityException  if a security manager exists and its
   4.237 +     *               <code>checkWrite</code> method denies
   4.238 +     *               write access to the file descriptor
   4.239 +     * @see        java.lang.SecurityManager#checkWrite(java.io.FileDescriptor)
   4.240 +     */
   4.241 +    public FileOutputStream(FileDescriptor fdObj) {
   4.242 +        SecurityManager security = System.getSecurityManager();
   4.243 +        if (fdObj == null) {
   4.244 +            throw new NullPointerException();
   4.245 +        }
   4.246 +        if (security != null) {
   4.247 +            security.checkWrite(fdObj);
   4.248 +        }
   4.249 +        this.fd = fdObj;
   4.250 +        this.append = false;
   4.251 +
   4.252 +        /*
   4.253 +         * FileDescriptor is being shared by streams.
   4.254 +         * Ensure that it's GC'ed only when all the streams/channels are done
   4.255 +         * using it.
   4.256 +         */
   4.257 +        fd.incrementAndGetUseCount();
   4.258 +    }
   4.259 +
   4.260 +    /**
   4.261 +     * Opens a file, with the specified name, for overwriting or appending.
   4.262 +     * @param name name of file to be opened
   4.263 +     * @param append whether the file is to be opened in append mode
   4.264 +     */
   4.265 +    private native void open(String name, boolean append)
   4.266 +        throws FileNotFoundException;
   4.267 +
   4.268 +    /**
   4.269 +     * Writes the specified byte to this file output stream.
   4.270 +     *
   4.271 +     * @param   b   the byte to be written.
   4.272 +     * @param   append   {@code true} if the write operation first
   4.273 +     *     advances the position to the end of file
   4.274 +     */
   4.275 +    private native void write(int b, boolean append) throws IOException;
   4.276 +
   4.277 +    /**
   4.278 +     * Writes the specified byte to this file output stream. Implements
   4.279 +     * the <code>write</code> method of <code>OutputStream</code>.
   4.280 +     *
   4.281 +     * @param      b   the byte to be written.
   4.282 +     * @exception  IOException  if an I/O error occurs.
   4.283 +     */
   4.284 +    public void write(int b) throws IOException {
   4.285 +        write(b, append);
   4.286 +    }
   4.287 +
   4.288 +    /**
   4.289 +     * Writes a sub array as a sequence of bytes.
   4.290 +     * @param b the data to be written
   4.291 +     * @param off the start offset in the data
   4.292 +     * @param len the number of bytes that are written
   4.293 +     * @param append {@code true} to first advance the position to the
   4.294 +     *     end of file
   4.295 +     * @exception IOException If an I/O error has occurred.
   4.296 +     */
   4.297 +    private native void writeBytes(byte b[], int off, int len, boolean append)
   4.298 +        throws IOException;
   4.299 +
   4.300 +    /**
   4.301 +     * Writes <code>b.length</code> bytes from the specified byte array
   4.302 +     * to this file output stream.
   4.303 +     *
   4.304 +     * @param      b   the data.
   4.305 +     * @exception  IOException  if an I/O error occurs.
   4.306 +     */
   4.307 +    public void write(byte b[]) throws IOException {
   4.308 +        writeBytes(b, 0, b.length, append);
   4.309 +    }
   4.310 +
   4.311 +    /**
   4.312 +     * Writes <code>len</code> bytes from the specified byte array
   4.313 +     * starting at offset <code>off</code> to this file output stream.
   4.314 +     *
   4.315 +     * @param      b     the data.
   4.316 +     * @param      off   the start offset in the data.
   4.317 +     * @param      len   the number of bytes to write.
   4.318 +     * @exception  IOException  if an I/O error occurs.
   4.319 +     */
   4.320 +    public void write(byte b[], int off, int len) throws IOException {
   4.321 +        writeBytes(b, off, len, append);
   4.322 +    }
   4.323 +
   4.324 +    /**
   4.325 +     * Closes this file output stream and releases any system resources
   4.326 +     * associated with this stream. This file output stream may no longer
   4.327 +     * be used for writing bytes.
   4.328 +     *
   4.329 +     * <p> If this stream has an associated channel then the channel is closed
   4.330 +     * as well.
   4.331 +     *
   4.332 +     * @exception  IOException  if an I/O error occurs.
   4.333 +     *
   4.334 +     * @revised 1.4
   4.335 +     * @spec JSR-51
   4.336 +     */
   4.337 +    public void close() throws IOException {
   4.338 +        synchronized (closeLock) {
   4.339 +            if (closed) {
   4.340 +                return;
   4.341 +            }
   4.342 +            closed = true;
   4.343 +        }
   4.344 +
   4.345 +        if (channel != null) {
   4.346 +            /*
   4.347 +             * Decrement FD use count associated with the channel
   4.348 +             * The use count is incremented whenever a new channel
   4.349 +             * is obtained from this stream.
   4.350 +             */
   4.351 +            fd.decrementAndGetUseCount();
   4.352 +            channel.close();
   4.353 +        }
   4.354 +
   4.355 +        /*
   4.356 +         * Decrement FD use count associated with this stream
   4.357 +         */
   4.358 +        int useCount = fd.decrementAndGetUseCount();
   4.359 +
   4.360 +        /*
   4.361 +         * If FileDescriptor is still in use by another stream, the finalizer
   4.362 +         * will not close it.
   4.363 +         */
   4.364 +        if ((useCount <= 0) || !isRunningFinalize()) {
   4.365 +            close0();
   4.366 +        }
   4.367 +    }
   4.368 +
   4.369 +    /**
   4.370 +     * Returns the file descriptor associated with this stream.
   4.371 +     *
   4.372 +     * @return  the <code>FileDescriptor</code> object that represents
   4.373 +     *          the connection to the file in the file system being used
   4.374 +     *          by this <code>FileOutputStream</code> object.
   4.375 +     *
   4.376 +     * @exception  IOException  if an I/O error occurs.
   4.377 +     * @see        java.io.FileDescriptor
   4.378 +     */
   4.379 +     public final FileDescriptor getFD()  throws IOException {
   4.380 +        if (fd != null) return fd;
   4.381 +        throw new IOException();
   4.382 +     }
   4.383 +
   4.384 +    /**
   4.385 +     * Returns the unique {@link java.nio.channels.FileChannel FileChannel}
   4.386 +     * object associated with this file output stream. </p>
   4.387 +     *
   4.388 +     * <p> The initial {@link java.nio.channels.FileChannel#position()
   4.389 +     * </code>position<code>} of the returned channel will be equal to the
   4.390 +     * number of bytes written to the file so far unless this stream is in
   4.391 +     * append mode, in which case it will be equal to the size of the file.
   4.392 +     * Writing bytes to this stream will increment the channel's position
   4.393 +     * accordingly.  Changing the channel's position, either explicitly or by
   4.394 +     * writing, will change this stream's file position.
   4.395 +     *
   4.396 +     * @return  the file channel associated with this file output stream
   4.397 +     *
   4.398 +     * @since 1.4
   4.399 +     * @spec JSR-51
   4.400 +     */
   4.401 +    public FileChannel getChannel() {
   4.402 +        synchronized (this) {
   4.403 +            if (channel == null) {
   4.404 +                channel = FileChannelImpl.open(fd, false, true, append, this);
   4.405 +
   4.406 +                /*
   4.407 +                 * Increment fd's use count. Invoking the channel's close()
   4.408 +                 * method will result in decrementing the use count set for
   4.409 +                 * the channel.
   4.410 +                 */
   4.411 +                fd.incrementAndGetUseCount();
   4.412 +            }
   4.413 +            return channel;
   4.414 +        }
   4.415 +    }
   4.416 +
   4.417 +    /**
   4.418 +     * Cleans up the connection to the file, and ensures that the
   4.419 +     * <code>close</code> method of this file output stream is
   4.420 +     * called when there are no more references to this stream.
   4.421 +     *
   4.422 +     * @exception  IOException  if an I/O error occurs.
   4.423 +     * @see        java.io.FileInputStream#close()
   4.424 +     */
   4.425 +    protected void finalize() throws IOException {
   4.426 +        if (fd != null) {
   4.427 +            if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
   4.428 +                flush();
   4.429 +            } else {
   4.430 +
   4.431 +                /*
   4.432 +                 * Finalizer should not release the FileDescriptor if another
   4.433 +                 * stream is still using it. If the user directly invokes
   4.434 +                 * close() then the FileDescriptor is also released.
   4.435 +                 */
   4.436 +                runningFinalize.set(Boolean.TRUE);
   4.437 +                try {
   4.438 +                    close();
   4.439 +                } finally {
   4.440 +                    runningFinalize.set(Boolean.FALSE);
   4.441 +                }
   4.442 +            }
   4.443 +        }
   4.444 +    }
   4.445 +
   4.446 +    private native void close0() throws IOException;
   4.447 +
   4.448 +    private static native void initIDs();
   4.449 +
   4.450 +    static {
   4.451 +        initIDs();
   4.452 +    }
   4.453 +
   4.454 +}
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/rt/emul/compact/src/main/java/java/io/FileReader.java	Thu Oct 03 15:40:35 2013 +0200
     5.3 @@ -0,0 +1,85 @@
     5.4 +/*
     5.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
     5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     5.7 + *
     5.8 + * This code is free software; you can redistribute it and/or modify it
     5.9 + * under the terms of the GNU General Public License version 2 only, as
    5.10 + * published by the Free Software Foundation.  Oracle designates this
    5.11 + * particular file as subject to the "Classpath" exception as provided
    5.12 + * by Oracle in the LICENSE file that accompanied this code.
    5.13 + *
    5.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    5.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    5.17 + * version 2 for more details (a copy is included in the LICENSE file that
    5.18 + * accompanied this code).
    5.19 + *
    5.20 + * You should have received a copy of the GNU General Public License version
    5.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    5.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    5.23 + *
    5.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    5.25 + * or visit www.oracle.com if you need additional information or have any
    5.26 + * questions.
    5.27 + */
    5.28 +
    5.29 +package java.io;
    5.30 +
    5.31 +
    5.32 +/**
    5.33 + * Convenience class for reading character files.  The constructors of this
    5.34 + * class assume that the default character encoding and the default byte-buffer
    5.35 + * size are appropriate.  To specify these values yourself, construct an
    5.36 + * InputStreamReader on a FileInputStream.
    5.37 + *
    5.38 + * <p><code>FileReader</code> is meant for reading streams of characters.
    5.39 + * For reading streams of raw bytes, consider using a
    5.40 + * <code>FileInputStream</code>.
    5.41 + *
    5.42 + * @see InputStreamReader
    5.43 + * @see FileInputStream
    5.44 + *
    5.45 + * @author      Mark Reinhold
    5.46 + * @since       JDK1.1
    5.47 + */
    5.48 +public class FileReader extends InputStreamReader {
    5.49 +
    5.50 +   /**
    5.51 +    * Creates a new <tt>FileReader</tt>, given the name of the
    5.52 +    * file to read from.
    5.53 +    *
    5.54 +    * @param fileName the name of the file to read from
    5.55 +    * @exception  FileNotFoundException  if the named file does not exist,
    5.56 +    *                   is a directory rather than a regular file,
    5.57 +    *                   or for some other reason cannot be opened for
    5.58 +    *                   reading.
    5.59 +    */
    5.60 +    public FileReader(String fileName) throws FileNotFoundException {
    5.61 +        super(new FileInputStream(fileName));
    5.62 +    }
    5.63 +
    5.64 +   /**
    5.65 +    * Creates a new <tt>FileReader</tt>, given the <tt>File</tt>
    5.66 +    * to read from.
    5.67 +    *
    5.68 +    * @param file the <tt>File</tt> to read from
    5.69 +    * @exception  FileNotFoundException  if the file does not exist,
    5.70 +    *                   is a directory rather than a regular file,
    5.71 +    *                   or for some other reason cannot be opened for
    5.72 +    *                   reading.
    5.73 +    */
    5.74 +    public FileReader(File file) throws FileNotFoundException {
    5.75 +        super(new FileInputStream(file));
    5.76 +    }
    5.77 +
    5.78 +   /**
    5.79 +    * Creates a new <tt>FileReader</tt>, given the
    5.80 +    * <tt>FileDescriptor</tt> to read from.
    5.81 +    *
    5.82 +    * @param fd the FileDescriptor to read from
    5.83 +    */
    5.84 +    public FileReader(FileDescriptor fd) {
    5.85 +        super(new FileInputStream(fd));
    5.86 +    }
    5.87 +
    5.88 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/rt/emul/compact/src/main/java/java/io/FileWriter.java	Thu Oct 03 15:40:35 2013 +0200
     6.3 @@ -0,0 +1,119 @@
     6.4 +/*
     6.5 + * Copyright (c) 1996, 2001, Oracle and/or its affiliates. All rights reserved.
     6.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     6.7 + *
     6.8 + * This code is free software; you can redistribute it and/or modify it
     6.9 + * under the terms of the GNU General Public License version 2 only, as
    6.10 + * published by the Free Software Foundation.  Oracle designates this
    6.11 + * particular file as subject to the "Classpath" exception as provided
    6.12 + * by Oracle in the LICENSE file that accompanied this code.
    6.13 + *
    6.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    6.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    6.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    6.17 + * version 2 for more details (a copy is included in the LICENSE file that
    6.18 + * accompanied this code).
    6.19 + *
    6.20 + * You should have received a copy of the GNU General Public License version
    6.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    6.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    6.23 + *
    6.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    6.25 + * or visit www.oracle.com if you need additional information or have any
    6.26 + * questions.
    6.27 + */
    6.28 +
    6.29 +package java.io;
    6.30 +
    6.31 +
    6.32 +/**
    6.33 + * Convenience class for writing character files.  The constructors of this
    6.34 + * class assume that the default character encoding and the default byte-buffer
    6.35 + * size are acceptable.  To specify these values yourself, construct an
    6.36 + * OutputStreamWriter on a FileOutputStream.
    6.37 + *
    6.38 + * <p>Whether or not a file is available or may be created depends upon the
    6.39 + * underlying platform.  Some platforms, in particular, allow a file to be
    6.40 + * opened for writing by only one <tt>FileWriter</tt> (or other file-writing
    6.41 + * object) at a time.  In such situations the constructors in this class
    6.42 + * will fail if the file involved is already open.
    6.43 + *
    6.44 + * <p><code>FileWriter</code> is meant for writing streams of characters.
    6.45 + * For writing streams of raw bytes, consider using a
    6.46 + * <code>FileOutputStream</code>.
    6.47 + *
    6.48 + * @see OutputStreamWriter
    6.49 + * @see FileOutputStream
    6.50 + *
    6.51 + * @author      Mark Reinhold
    6.52 + * @since       JDK1.1
    6.53 + */
    6.54 +
    6.55 +public class FileWriter extends OutputStreamWriter {
    6.56 +
    6.57 +    /**
    6.58 +     * Constructs a FileWriter object given a file name.
    6.59 +     *
    6.60 +     * @param fileName  String The system-dependent filename.
    6.61 +     * @throws IOException  if the named file exists but is a directory rather
    6.62 +     *                  than a regular file, does not exist but cannot be
    6.63 +     *                  created, or cannot be opened for any other reason
    6.64 +     */
    6.65 +    public FileWriter(String fileName) throws IOException {
    6.66 +        super(new FileOutputStream(fileName));
    6.67 +    }
    6.68 +
    6.69 +    /**
    6.70 +     * Constructs a FileWriter object given a file name with a boolean
    6.71 +     * indicating whether or not to append the data written.
    6.72 +     *
    6.73 +     * @param fileName  String The system-dependent filename.
    6.74 +     * @param append    boolean if <code>true</code>, then data will be written
    6.75 +     *                  to the end of the file rather than the beginning.
    6.76 +     * @throws IOException  if the named file exists but is a directory rather
    6.77 +     *                  than a regular file, does not exist but cannot be
    6.78 +     *                  created, or cannot be opened for any other reason
    6.79 +     */
    6.80 +    public FileWriter(String fileName, boolean append) throws IOException {
    6.81 +        super(new FileOutputStream(fileName, append));
    6.82 +    }
    6.83 +
    6.84 +    /**
    6.85 +     * Constructs a FileWriter object given a File object.
    6.86 +     *
    6.87 +     * @param file  a File object to write to.
    6.88 +     * @throws IOException  if the file exists but is a directory rather than
    6.89 +     *                  a regular file, does not exist but cannot be created,
    6.90 +     *                  or cannot be opened for any other reason
    6.91 +     */
    6.92 +    public FileWriter(File file) throws IOException {
    6.93 +        super(new FileOutputStream(file));
    6.94 +    }
    6.95 +
    6.96 +    /**
    6.97 +     * Constructs a FileWriter object given a File object. If the second
    6.98 +     * argument is <code>true</code>, then bytes will be written to the end
    6.99 +     * of the file rather than the beginning.
   6.100 +     *
   6.101 +     * @param file  a File object to write to
   6.102 +     * @param     append    if <code>true</code>, then bytes will be written
   6.103 +     *                      to the end of the file rather than the beginning
   6.104 +     * @throws IOException  if the file exists but is a directory rather than
   6.105 +     *                  a regular file, does not exist but cannot be created,
   6.106 +     *                  or cannot be opened for any other reason
   6.107 +     * @since 1.4
   6.108 +     */
   6.109 +    public FileWriter(File file, boolean append) throws IOException {
   6.110 +        super(new FileOutputStream(file, append));
   6.111 +    }
   6.112 +
   6.113 +    /**
   6.114 +     * Constructs a FileWriter object associated with a file descriptor.
   6.115 +     *
   6.116 +     * @param fd  FileDescriptor object to write to.
   6.117 +     */
   6.118 +    public FileWriter(FileDescriptor fd) {
   6.119 +        super(new FileOutputStream(fd));
   6.120 +    }
   6.121 +
   6.122 +}
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberInputStream.java	Thu Oct 03 15:40:35 2013 +0200
     7.3 @@ -0,0 +1,292 @@
     7.4 +/*
     7.5 + * Copyright (c) 1995, 2004, Oracle and/or its affiliates. All rights reserved.
     7.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     7.7 + *
     7.8 + * This code is free software; you can redistribute it and/or modify it
     7.9 + * under the terms of the GNU General Public License version 2 only, as
    7.10 + * published by the Free Software Foundation.  Oracle designates this
    7.11 + * particular file as subject to the "Classpath" exception as provided
    7.12 + * by Oracle in the LICENSE file that accompanied this code.
    7.13 + *
    7.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    7.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    7.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    7.17 + * version 2 for more details (a copy is included in the LICENSE file that
    7.18 + * accompanied this code).
    7.19 + *
    7.20 + * You should have received a copy of the GNU General Public License version
    7.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    7.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    7.23 + *
    7.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    7.25 + * or visit www.oracle.com if you need additional information or have any
    7.26 + * questions.
    7.27 + */
    7.28 +
    7.29 +package java.io;
    7.30 +
    7.31 +/**
    7.32 + * This class is an input stream filter that provides the added
    7.33 + * functionality of keeping track of the current line number.
    7.34 + * <p>
    7.35 + * A line is a sequence of bytes ending with a carriage return
    7.36 + * character (<code>'&#92;r'</code>), a newline character
    7.37 + * (<code>'&#92;n'</code>), or a carriage return character followed
    7.38 + * immediately by a linefeed character. In all three cases, the line
    7.39 + * terminating character(s) are returned as a single newline character.
    7.40 + * <p>
    7.41 + * The line number begins at <code>0</code>, and is incremented by
    7.42 + * <code>1</code> when a <code>read</code> returns a newline character.
    7.43 + *
    7.44 + * @author     Arthur van Hoff
    7.45 + * @see        java.io.LineNumberReader
    7.46 + * @since      JDK1.0
    7.47 + * @deprecated This class incorrectly assumes that bytes adequately represent
    7.48 + *             characters.  As of JDK&nbsp;1.1, the preferred way to operate on
    7.49 + *             character streams is via the new character-stream classes, which
    7.50 + *             include a class for counting line numbers.
    7.51 + */
    7.52 +@Deprecated
    7.53 +public
    7.54 +class LineNumberInputStream extends FilterInputStream {
    7.55 +    int pushBack = -1;
    7.56 +    int lineNumber;
    7.57 +    int markLineNumber;
    7.58 +    int markPushBack = -1;
    7.59 +
    7.60 +    /**
    7.61 +     * Constructs a newline number input stream that reads its input
    7.62 +     * from the specified input stream.
    7.63 +     *
    7.64 +     * @param      in   the underlying input stream.
    7.65 +     */
    7.66 +    public LineNumberInputStream(InputStream in) {
    7.67 +        super(in);
    7.68 +    }
    7.69 +
    7.70 +    /**
    7.71 +     * Reads the next byte of data from this input stream. The value
    7.72 +     * byte is returned as an <code>int</code> in the range
    7.73 +     * <code>0</code> to <code>255</code>. If no byte is available
    7.74 +     * because the end of the stream has been reached, the value
    7.75 +     * <code>-1</code> is returned. This method blocks until input data
    7.76 +     * is available, the end of the stream is detected, or an exception
    7.77 +     * is thrown.
    7.78 +     * <p>
    7.79 +     * The <code>read</code> method of
    7.80 +     * <code>LineNumberInputStream</code> calls the <code>read</code>
    7.81 +     * method of the underlying input stream. It checks for carriage
    7.82 +     * returns and newline characters in the input, and modifies the
    7.83 +     * current line number as appropriate. A carriage-return character or
    7.84 +     * a carriage return followed by a newline character are both
    7.85 +     * converted into a single newline character.
    7.86 +     *
    7.87 +     * @return     the next byte of data, or <code>-1</code> if the end of this
    7.88 +     *             stream is reached.
    7.89 +     * @exception  IOException  if an I/O error occurs.
    7.90 +     * @see        java.io.FilterInputStream#in
    7.91 +     * @see        java.io.LineNumberInputStream#getLineNumber()
    7.92 +     */
    7.93 +    public int read() throws IOException {
    7.94 +        int c = pushBack;
    7.95 +
    7.96 +        if (c != -1) {
    7.97 +            pushBack = -1;
    7.98 +        } else {
    7.99 +            c = in.read();
   7.100 +        }
   7.101 +
   7.102 +        switch (c) {
   7.103 +          case '\r':
   7.104 +            pushBack = in.read();
   7.105 +            if (pushBack == '\n') {
   7.106 +                pushBack = -1;
   7.107 +            }
   7.108 +          case '\n':
   7.109 +            lineNumber++;
   7.110 +            return '\n';
   7.111 +        }
   7.112 +        return c;
   7.113 +    }
   7.114 +
   7.115 +    /**
   7.116 +     * Reads up to <code>len</code> bytes of data from this input stream
   7.117 +     * into an array of bytes. This method blocks until some input is available.
   7.118 +     * <p>
   7.119 +     * The <code>read</code> method of
   7.120 +     * <code>LineNumberInputStream</code> repeatedly calls the
   7.121 +     * <code>read</code> method of zero arguments to fill in the byte array.
   7.122 +     *
   7.123 +     * @param      b     the buffer into which the data is read.
   7.124 +     * @param      off   the start offset of the data.
   7.125 +     * @param      len   the maximum number of bytes read.
   7.126 +     * @return     the total number of bytes read into the buffer, or
   7.127 +     *             <code>-1</code> if there is no more data because the end of
   7.128 +     *             this stream has been reached.
   7.129 +     * @exception  IOException  if an I/O error occurs.
   7.130 +     * @see        java.io.LineNumberInputStream#read()
   7.131 +     */
   7.132 +    public int read(byte b[], int off, int len) throws IOException {
   7.133 +        if (b == null) {
   7.134 +            throw new NullPointerException();
   7.135 +        } else if ((off < 0) || (off > b.length) || (len < 0) ||
   7.136 +                   ((off + len) > b.length) || ((off + len) < 0)) {
   7.137 +            throw new IndexOutOfBoundsException();
   7.138 +        } else if (len == 0) {
   7.139 +            return 0;
   7.140 +        }
   7.141 +
   7.142 +        int c = read();
   7.143 +        if (c == -1) {
   7.144 +            return -1;
   7.145 +        }
   7.146 +        b[off] = (byte)c;
   7.147 +
   7.148 +        int i = 1;
   7.149 +        try {
   7.150 +            for (; i < len ; i++) {
   7.151 +                c = read();
   7.152 +                if (c == -1) {
   7.153 +                    break;
   7.154 +                }
   7.155 +                if (b != null) {
   7.156 +                    b[off + i] = (byte)c;
   7.157 +                }
   7.158 +            }
   7.159 +        } catch (IOException ee) {
   7.160 +        }
   7.161 +        return i;
   7.162 +    }
   7.163 +
   7.164 +    /**
   7.165 +     * Skips over and discards <code>n</code> bytes of data from this
   7.166 +     * input stream. The <code>skip</code> method may, for a variety of
   7.167 +     * reasons, end up skipping over some smaller number of bytes,
   7.168 +     * possibly <code>0</code>. The actual number of bytes skipped is
   7.169 +     * returned.  If <code>n</code> is negative, no bytes are skipped.
   7.170 +     * <p>
   7.171 +     * The <code>skip</code> method of <code>LineNumberInputStream</code> creates
   7.172 +     * a byte array and then repeatedly reads into it until
   7.173 +     * <code>n</code> bytes have been read or the end of the stream has
   7.174 +     * been reached.
   7.175 +     *
   7.176 +     * @param      n   the number of bytes to be skipped.
   7.177 +     * @return     the actual number of bytes skipped.
   7.178 +     * @exception  IOException  if an I/O error occurs.
   7.179 +     * @see        java.io.FilterInputStream#in
   7.180 +     */
   7.181 +    public long skip(long n) throws IOException {
   7.182 +        int chunk = 2048;
   7.183 +        long remaining = n;
   7.184 +        byte data[];
   7.185 +        int nr;
   7.186 +
   7.187 +        if (n <= 0) {
   7.188 +            return 0;
   7.189 +        }
   7.190 +
   7.191 +        data = new byte[chunk];
   7.192 +        while (remaining > 0) {
   7.193 +            nr = read(data, 0, (int) Math.min(chunk, remaining));
   7.194 +            if (nr < 0) {
   7.195 +                break;
   7.196 +            }
   7.197 +            remaining -= nr;
   7.198 +        }
   7.199 +
   7.200 +        return n - remaining;
   7.201 +    }
   7.202 +
   7.203 +    /**
   7.204 +     * Sets the line number to the specified argument.
   7.205 +     *
   7.206 +     * @param      lineNumber   the new line number.
   7.207 +     * @see #getLineNumber
   7.208 +     */
   7.209 +    public void setLineNumber(int lineNumber) {
   7.210 +        this.lineNumber = lineNumber;
   7.211 +    }
   7.212 +
   7.213 +    /**
   7.214 +     * Returns the current line number.
   7.215 +     *
   7.216 +     * @return     the current line number.
   7.217 +     * @see #setLineNumber
   7.218 +     */
   7.219 +    public int getLineNumber() {
   7.220 +        return lineNumber;
   7.221 +    }
   7.222 +
   7.223 +
   7.224 +    /**
   7.225 +     * Returns the number of bytes that can be read from this input
   7.226 +     * stream without blocking.
   7.227 +     * <p>
   7.228 +     * Note that if the underlying input stream is able to supply
   7.229 +     * <i>k</i> input characters without blocking, the
   7.230 +     * <code>LineNumberInputStream</code> can guarantee only to provide
   7.231 +     * <i>k</i>/2 characters without blocking, because the
   7.232 +     * <i>k</i> characters from the underlying input stream might
   7.233 +     * consist of <i>k</i>/2 pairs of <code>'&#92;r'</code> and
   7.234 +     * <code>'&#92;n'</code>, which are converted to just
   7.235 +     * <i>k</i>/2 <code>'&#92;n'</code> characters.
   7.236 +     *
   7.237 +     * @return     the number of bytes that can be read from this input stream
   7.238 +     *             without blocking.
   7.239 +     * @exception  IOException  if an I/O error occurs.
   7.240 +     * @see        java.io.FilterInputStream#in
   7.241 +     */
   7.242 +    public int available() throws IOException {
   7.243 +        return (pushBack == -1) ? super.available()/2 : super.available()/2 + 1;
   7.244 +    }
   7.245 +
   7.246 +    /**
   7.247 +     * Marks the current position in this input stream. A subsequent
   7.248 +     * call to the <code>reset</code> method repositions this stream at
   7.249 +     * the last marked position so that subsequent reads re-read the same bytes.
   7.250 +     * <p>
   7.251 +     * The <code>mark</code> method of
   7.252 +     * <code>LineNumberInputStream</code> remembers the current line
   7.253 +     * number in a private variable, and then calls the <code>mark</code>
   7.254 +     * method of the underlying input stream.
   7.255 +     *
   7.256 +     * @param   readlimit   the maximum limit of bytes that can be read before
   7.257 +     *                      the mark position becomes invalid.
   7.258 +     * @see     java.io.FilterInputStream#in
   7.259 +     * @see     java.io.LineNumberInputStream#reset()
   7.260 +     */
   7.261 +    public void mark(int readlimit) {
   7.262 +        markLineNumber = lineNumber;
   7.263 +        markPushBack   = pushBack;
   7.264 +        in.mark(readlimit);
   7.265 +    }
   7.266 +
   7.267 +    /**
   7.268 +     * Repositions this stream to the position at the time the
   7.269 +     * <code>mark</code> method was last called on this input stream.
   7.270 +     * <p>
   7.271 +     * The <code>reset</code> method of
   7.272 +     * <code>LineNumberInputStream</code> resets the line number to be
   7.273 +     * the line number at the time the <code>mark</code> method was
   7.274 +     * called, and then calls the <code>reset</code> method of the
   7.275 +     * underlying input stream.
   7.276 +     * <p>
   7.277 +     * Stream marks are intended to be used in
   7.278 +     * situations where you need to read ahead a little to see what's in
   7.279 +     * the stream. Often this is most easily done by invoking some
   7.280 +     * general parser. If the stream is of the type handled by the
   7.281 +     * parser, it just chugs along happily. If the stream is not of
   7.282 +     * that type, the parser should toss an exception when it fails,
   7.283 +     * which, if it happens within readlimit bytes, allows the outer
   7.284 +     * code to reset the stream and try another parser.
   7.285 +     *
   7.286 +     * @exception  IOException  if an I/O error occurs.
   7.287 +     * @see        java.io.FilterInputStream#in
   7.288 +     * @see        java.io.LineNumberInputStream#mark(int)
   7.289 +     */
   7.290 +    public void reset() throws IOException {
   7.291 +        lineNumber = markLineNumber;
   7.292 +        pushBack   = markPushBack;
   7.293 +        in.reset();
   7.294 +    }
   7.295 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/rt/emul/compact/src/main/java/java/io/LineNumberReader.java	Thu Oct 03 15:40:35 2013 +0200
     8.3 @@ -0,0 +1,281 @@
     8.4 +/*
     8.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
     8.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     8.7 + *
     8.8 + * This code is free software; you can redistribute it and/or modify it
     8.9 + * under the terms of the GNU General Public License version 2 only, as
    8.10 + * published by the Free Software Foundation.  Oracle designates this
    8.11 + * particular file as subject to the "Classpath" exception as provided
    8.12 + * by Oracle in the LICENSE file that accompanied this code.
    8.13 + *
    8.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    8.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    8.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    8.17 + * version 2 for more details (a copy is included in the LICENSE file that
    8.18 + * accompanied this code).
    8.19 + *
    8.20 + * You should have received a copy of the GNU General Public License version
    8.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    8.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    8.23 + *
    8.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    8.25 + * or visit www.oracle.com if you need additional information or have any
    8.26 + * questions.
    8.27 + */
    8.28 +
    8.29 +package java.io;
    8.30 +
    8.31 +
    8.32 +/**
    8.33 + * A buffered character-input stream that keeps track of line numbers.  This
    8.34 + * class defines methods {@link #setLineNumber(int)} and {@link
    8.35 + * #getLineNumber()} for setting and getting the current line number
    8.36 + * respectively.
    8.37 + *
    8.38 + * <p> By default, line numbering begins at 0. This number increments at every
    8.39 + * <a href="#lt">line terminator</a> as the data is read, and can be changed
    8.40 + * with a call to <tt>setLineNumber(int)</tt>.  Note however, that
    8.41 + * <tt>setLineNumber(int)</tt> does not actually change the current position in
    8.42 + * the stream; it only changes the value that will be returned by
    8.43 + * <tt>getLineNumber()</tt>.
    8.44 + *
    8.45 + * <p> A line is considered to be <a name="lt">terminated</a> by any one of a
    8.46 + * line feed ('\n'), a carriage return ('\r'), or a carriage return followed
    8.47 + * immediately by a linefeed.
    8.48 + *
    8.49 + * @author      Mark Reinhold
    8.50 + * @since       JDK1.1
    8.51 + */
    8.52 +
    8.53 +public class LineNumberReader extends BufferedReader {
    8.54 +
    8.55 +    /** The current line number */
    8.56 +    private int lineNumber = 0;
    8.57 +
    8.58 +    /** The line number of the mark, if any */
    8.59 +    private int markedLineNumber; // Defaults to 0
    8.60 +
    8.61 +    /** If the next character is a line feed, skip it */
    8.62 +    private boolean skipLF;
    8.63 +
    8.64 +    /** The skipLF flag when the mark was set */
    8.65 +    private boolean markedSkipLF;
    8.66 +
    8.67 +    /**
    8.68 +     * Create a new line-numbering reader, using the default input-buffer
    8.69 +     * size.
    8.70 +     *
    8.71 +     * @param  in
    8.72 +     *         A Reader object to provide the underlying stream
    8.73 +     */
    8.74 +    public LineNumberReader(Reader in) {
    8.75 +        super(in);
    8.76 +    }
    8.77 +
    8.78 +    /**
    8.79 +     * Create a new line-numbering reader, reading characters into a buffer of
    8.80 +     * the given size.
    8.81 +     *
    8.82 +     * @param  in
    8.83 +     *         A Reader object to provide the underlying stream
    8.84 +     *
    8.85 +     * @param  sz
    8.86 +     *         An int specifying the size of the buffer
    8.87 +     */
    8.88 +    public LineNumberReader(Reader in, int sz) {
    8.89 +        super(in, sz);
    8.90 +    }
    8.91 +
    8.92 +    /**
    8.93 +     * Set the current line number.
    8.94 +     *
    8.95 +     * @param  lineNumber
    8.96 +     *         An int specifying the line number
    8.97 +     *
    8.98 +     * @see #getLineNumber
    8.99 +     */
   8.100 +    public void setLineNumber(int lineNumber) {
   8.101 +        this.lineNumber = lineNumber;
   8.102 +    }
   8.103 +
   8.104 +    /**
   8.105 +     * Get the current line number.
   8.106 +     *
   8.107 +     * @return  The current line number
   8.108 +     *
   8.109 +     * @see #setLineNumber
   8.110 +     */
   8.111 +    public int getLineNumber() {
   8.112 +        return lineNumber;
   8.113 +    }
   8.114 +
   8.115 +    /**
   8.116 +     * Read a single character.  <a href="#lt">Line terminators</a> are
   8.117 +     * compressed into single newline ('\n') characters.  Whenever a line
   8.118 +     * terminator is read the current line number is incremented.
   8.119 +     *
   8.120 +     * @return  The character read, or -1 if the end of the stream has been
   8.121 +     *          reached
   8.122 +     *
   8.123 +     * @throws  IOException
   8.124 +     *          If an I/O error occurs
   8.125 +     */
   8.126 +    public int read() throws IOException {
   8.127 +        synchronized (lock) {
   8.128 +            int c = super.read();
   8.129 +            if (skipLF) {
   8.130 +                if (c == '\n')
   8.131 +                    c = super.read();
   8.132 +                skipLF = false;
   8.133 +            }
   8.134 +            switch (c) {
   8.135 +            case '\r':
   8.136 +                skipLF = true;
   8.137 +            case '\n':          /* Fall through */
   8.138 +                lineNumber++;
   8.139 +                return '\n';
   8.140 +            }
   8.141 +            return c;
   8.142 +        }
   8.143 +    }
   8.144 +
   8.145 +    /**
   8.146 +     * Read characters into a portion of an array.  Whenever a <a
   8.147 +     * href="#lt">line terminator</a> is read the current line number is
   8.148 +     * incremented.
   8.149 +     *
   8.150 +     * @param  cbuf
   8.151 +     *         Destination buffer
   8.152 +     *
   8.153 +     * @param  off
   8.154 +     *         Offset at which to start storing characters
   8.155 +     *
   8.156 +     * @param  len
   8.157 +     *         Maximum number of characters to read
   8.158 +     *
   8.159 +     * @return  The number of bytes read, or -1 if the end of the stream has
   8.160 +     *          already been reached
   8.161 +     *
   8.162 +     * @throws  IOException
   8.163 +     *          If an I/O error occurs
   8.164 +     */
   8.165 +    public int read(char cbuf[], int off, int len) throws IOException {
   8.166 +        synchronized (lock) {
   8.167 +            int n = super.read(cbuf, off, len);
   8.168 +
   8.169 +            for (int i = off; i < off + n; i++) {
   8.170 +                int c = cbuf[i];
   8.171 +                if (skipLF) {
   8.172 +                    skipLF = false;
   8.173 +                    if (c == '\n')
   8.174 +                        continue;
   8.175 +                }
   8.176 +                switch (c) {
   8.177 +                case '\r':
   8.178 +                    skipLF = true;
   8.179 +                case '\n':      /* Fall through */
   8.180 +                    lineNumber++;
   8.181 +                    break;
   8.182 +                }
   8.183 +            }
   8.184 +
   8.185 +            return n;
   8.186 +        }
   8.187 +    }
   8.188 +
   8.189 +    /**
   8.190 +     * Read a line of text.  Whenever a <a href="#lt">line terminator</a> is
   8.191 +     * read the current line number is incremented.
   8.192 +     *
   8.193 +     * @return  A String containing the contents of the line, not including
   8.194 +     *          any <a href="#lt">line termination characters</a>, or
   8.195 +     *          <tt>null</tt> if the end of the stream has been reached
   8.196 +     *
   8.197 +     * @throws  IOException
   8.198 +     *          If an I/O error occurs
   8.199 +     */
   8.200 +    public String readLine() throws IOException {
   8.201 +        synchronized (lock) {
   8.202 +            String l = super.readLine(skipLF);
   8.203 +            skipLF = false;
   8.204 +            if (l != null)
   8.205 +                lineNumber++;
   8.206 +            return l;
   8.207 +        }
   8.208 +    }
   8.209 +
   8.210 +    /** Maximum skip-buffer size */
   8.211 +    private static final int maxSkipBufferSize = 8192;
   8.212 +
   8.213 +    /** Skip buffer, null until allocated */
   8.214 +    private char skipBuffer[] = null;
   8.215 +
   8.216 +    /**
   8.217 +     * Skip characters.
   8.218 +     *
   8.219 +     * @param  n
   8.220 +     *         The number of characters to skip
   8.221 +     *
   8.222 +     * @return  The number of characters actually skipped
   8.223 +     *
   8.224 +     * @throws  IOException
   8.225 +     *          If an I/O error occurs
   8.226 +     *
   8.227 +     * @throws  IllegalArgumentException
   8.228 +     *          If <tt>n</tt> is negative
   8.229 +     */
   8.230 +    public long skip(long n) throws IOException {
   8.231 +        if (n < 0)
   8.232 +            throw new IllegalArgumentException("skip() value is negative");
   8.233 +        int nn = (int) Math.min(n, maxSkipBufferSize);
   8.234 +        synchronized (lock) {
   8.235 +            if ((skipBuffer == null) || (skipBuffer.length < nn))
   8.236 +                skipBuffer = new char[nn];
   8.237 +            long r = n;
   8.238 +            while (r > 0) {
   8.239 +                int nc = read(skipBuffer, 0, (int) Math.min(r, nn));
   8.240 +                if (nc == -1)
   8.241 +                    break;
   8.242 +                r -= nc;
   8.243 +            }
   8.244 +            return n - r;
   8.245 +        }
   8.246 +    }
   8.247 +
   8.248 +    /**
   8.249 +     * Mark the present position in the stream.  Subsequent calls to reset()
   8.250 +     * will attempt to reposition the stream to this point, and will also reset
   8.251 +     * the line number appropriately.
   8.252 +     *
   8.253 +     * @param  readAheadLimit
   8.254 +     *         Limit on the number of characters that may be read while still
   8.255 +     *         preserving the mark.  After reading this many characters,
   8.256 +     *         attempting to reset the stream may fail.
   8.257 +     *
   8.258 +     * @throws  IOException
   8.259 +     *          If an I/O error occurs
   8.260 +     */
   8.261 +    public void mark(int readAheadLimit) throws IOException {
   8.262 +        synchronized (lock) {
   8.263 +            super.mark(readAheadLimit);
   8.264 +            markedLineNumber = lineNumber;
   8.265 +            markedSkipLF     = skipLF;
   8.266 +        }
   8.267 +    }
   8.268 +
   8.269 +    /**
   8.270 +     * Reset the stream to the most recent mark.
   8.271 +     *
   8.272 +     * @throws  IOException
   8.273 +     *          If the stream has not been marked, or if the mark has been
   8.274 +     *          invalidated
   8.275 +     */
   8.276 +    public void reset() throws IOException {
   8.277 +        synchronized (lock) {
   8.278 +            super.reset();
   8.279 +            lineNumber = markedLineNumber;
   8.280 +            skipLF     = markedSkipLF;
   8.281 +        }
   8.282 +    }
   8.283 +
   8.284 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/rt/emul/compact/src/main/java/java/io/SyncFailedException.java	Thu Oct 03 15:40:35 2013 +0200
     9.3 @@ -0,0 +1,48 @@
     9.4 +/*
     9.5 + * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
     9.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     9.7 + *
     9.8 + * This code is free software; you can redistribute it and/or modify it
     9.9 + * under the terms of the GNU General Public License version 2 only, as
    9.10 + * published by the Free Software Foundation.  Oracle designates this
    9.11 + * particular file as subject to the "Classpath" exception as provided
    9.12 + * by Oracle in the LICENSE file that accompanied this code.
    9.13 + *
    9.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
    9.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    9.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    9.17 + * version 2 for more details (a copy is included in the LICENSE file that
    9.18 + * accompanied this code).
    9.19 + *
    9.20 + * You should have received a copy of the GNU General Public License version
    9.21 + * 2 along with this work; if not, write to the Free Software Foundation,
    9.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    9.23 + *
    9.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    9.25 + * or visit www.oracle.com if you need additional information or have any
    9.26 + * questions.
    9.27 + */
    9.28 +
    9.29 +package java.io;
    9.30 +
    9.31 +/**
    9.32 + * Signals that a sync operation has failed.
    9.33 + *
    9.34 + * @author  Ken Arnold
    9.35 + * @see     java.io.FileDescriptor#sync
    9.36 + * @see     java.io.IOException
    9.37 + * @since   JDK1.1
    9.38 + */
    9.39 +public class SyncFailedException extends IOException {
    9.40 +    private static final long serialVersionUID = -2353342684412443330L;
    9.41 +
    9.42 +    /**
    9.43 +     * Constructs an SyncFailedException with a detail message.
    9.44 +     * A detail message is a String that describes this particular exception.
    9.45 +     *
    9.46 +     * @param desc  a String describing the exception.
    9.47 +     */
    9.48 +    public SyncFailedException(String desc) {
    9.49 +        super(desc);
    9.50 +    }
    9.51 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/Charset.java	Thu Oct 03 15:40:35 2013 +0200
    10.3 @@ -0,0 +1,923 @@
    10.4 +/*
    10.5 + * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
    10.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    10.7 + *
    10.8 + * This code is free software; you can redistribute it and/or modify it
    10.9 + * under the terms of the GNU General Public License version 2 only, as
   10.10 + * published by the Free Software Foundation.  Oracle designates this
   10.11 + * particular file as subject to the "Classpath" exception as provided
   10.12 + * by Oracle in the LICENSE file that accompanied this code.
   10.13 + *
   10.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   10.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   10.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   10.17 + * version 2 for more details (a copy is included in the LICENSE file that
   10.18 + * accompanied this code).
   10.19 + *
   10.20 + * You should have received a copy of the GNU General Public License version
   10.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   10.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   10.23 + *
   10.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   10.25 + * or visit www.oracle.com if you need additional information or have any
   10.26 + * questions.
   10.27 + */
   10.28 +
   10.29 +package java.nio.charset;
   10.30 +
   10.31 +import java.nio.ByteBuffer;
   10.32 +import java.nio.CharBuffer;
   10.33 +import java.nio.charset.spi.CharsetProvider;
   10.34 +import java.security.AccessController;
   10.35 +import java.security.AccessControlException;
   10.36 +import java.security.PrivilegedAction;
   10.37 +import java.util.Collections;
   10.38 +import java.util.HashSet;
   10.39 +import java.util.Iterator;
   10.40 +import java.util.Locale;
   10.41 +import java.util.Map;
   10.42 +import java.util.NoSuchElementException;
   10.43 +import java.util.Set;
   10.44 +import java.util.ServiceLoader;
   10.45 +import java.util.ServiceConfigurationError;
   10.46 +import java.util.SortedMap;
   10.47 +import java.util.TreeMap;
   10.48 +import sun.misc.ASCIICaseInsensitiveComparator;
   10.49 +import sun.nio.cs.StandardCharsets;
   10.50 +import sun.nio.cs.ThreadLocalCoders;
   10.51 +import sun.security.action.GetPropertyAction;
   10.52 +
   10.53 +
   10.54 +/**
   10.55 + * A named mapping between sequences of sixteen-bit Unicode <a
   10.56 + * href="../../lang/Character.html#unicode">code units</a> and sequences of
   10.57 + * bytes.  This class defines methods for creating decoders and encoders and
   10.58 + * for retrieving the various names associated with a charset.  Instances of
   10.59 + * this class are immutable.
   10.60 + *
   10.61 + * <p> This class also defines static methods for testing whether a particular
   10.62 + * charset is supported, for locating charset instances by name, and for
   10.63 + * constructing a map that contains every charset for which support is
   10.64 + * available in the current Java virtual machine.  Support for new charsets can
   10.65 + * be added via the service-provider interface defined in the {@link
   10.66 + * java.nio.charset.spi.CharsetProvider} class.
   10.67 + *
   10.68 + * <p> All of the methods defined in this class are safe for use by multiple
   10.69 + * concurrent threads.
   10.70 + *
   10.71 + *
   10.72 + * <a name="names"><a name="charenc">
   10.73 + * <h4>Charset names</h4>
   10.74 + *
   10.75 + * <p> Charsets are named by strings composed of the following characters:
   10.76 + *
   10.77 + * <ul>
   10.78 + *
   10.79 + *   <li> The uppercase letters <tt>'A'</tt> through <tt>'Z'</tt>
   10.80 + *        (<tt>'&#92;u0041'</tt>&nbsp;through&nbsp;<tt>'&#92;u005a'</tt>),
   10.81 + *
   10.82 + *   <li> The lowercase letters <tt>'a'</tt> through <tt>'z'</tt>
   10.83 + *        (<tt>'&#92;u0061'</tt>&nbsp;through&nbsp;<tt>'&#92;u007a'</tt>),
   10.84 + *
   10.85 + *   <li> The digits <tt>'0'</tt> through <tt>'9'</tt>
   10.86 + *        (<tt>'&#92;u0030'</tt>&nbsp;through&nbsp;<tt>'&#92;u0039'</tt>),
   10.87 + *
   10.88 + *   <li> The dash character <tt>'-'</tt>
   10.89 + *        (<tt>'&#92;u002d'</tt>,&nbsp;<small>HYPHEN-MINUS</small>),
   10.90 + *
   10.91 + *   <li> The plus character <tt>'+'</tt>
   10.92 + *        (<tt>'&#92;u002b'</tt>,&nbsp;<small>PLUS SIGN</small>),
   10.93 + *
   10.94 + *   <li> The period character <tt>'.'</tt>
   10.95 + *        (<tt>'&#92;u002e'</tt>,&nbsp;<small>FULL STOP</small>),
   10.96 + *
   10.97 + *   <li> The colon character <tt>':'</tt>
   10.98 + *        (<tt>'&#92;u003a'</tt>,&nbsp;<small>COLON</small>), and
   10.99 + *
  10.100 + *   <li> The underscore character <tt>'_'</tt>
  10.101 + *        (<tt>'&#92;u005f'</tt>,&nbsp;<small>LOW&nbsp;LINE</small>).
  10.102 + *
  10.103 + * </ul>
  10.104 + *
  10.105 + * A charset name must begin with either a letter or a digit.  The empty string
  10.106 + * is not a legal charset name.  Charset names are not case-sensitive; that is,
  10.107 + * case is always ignored when comparing charset names.  Charset names
  10.108 + * generally follow the conventions documented in <a
  10.109 + * href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278:&nbsp;IANA Charset
  10.110 + * Registration Procedures</i></a>.
  10.111 + *
  10.112 + * <p> Every charset has a <i>canonical name</i> and may also have one or more
  10.113 + * <i>aliases</i>.  The canonical name is returned by the {@link #name() name} method
  10.114 + * of this class.  Canonical names are, by convention, usually in upper case.
  10.115 + * The aliases of a charset are returned by the {@link #aliases() aliases}
  10.116 + * method.
  10.117 + *
  10.118 + * <a name="hn">
  10.119 + *
  10.120 + * <p> Some charsets have an <i>historical name</i> that is defined for
  10.121 + * compatibility with previous versions of the Java platform.  A charset's
  10.122 + * historical name is either its canonical name or one of its aliases.  The
  10.123 + * historical name is returned by the <tt>getEncoding()</tt> methods of the
  10.124 + * {@link java.io.InputStreamReader#getEncoding InputStreamReader} and {@link
  10.125 + * java.io.OutputStreamWriter#getEncoding OutputStreamWriter} classes.
  10.126 + *
  10.127 + * <a name="iana">
  10.128 + *
  10.129 + * <p> If a charset listed in the <a
  10.130 + * href="http://www.iana.org/assignments/character-sets"><i>IANA Charset
  10.131 + * Registry</i></a> is supported by an implementation of the Java platform then
  10.132 + * its canonical name must be the name listed in the registry.  Many charsets
  10.133 + * are given more than one name in the registry, in which case the registry
  10.134 + * identifies one of the names as <i>MIME-preferred</i>.  If a charset has more
  10.135 + * than one registry name then its canonical name must be the MIME-preferred
  10.136 + * name and the other names in the registry must be valid aliases.  If a
  10.137 + * supported charset is not listed in the IANA registry then its canonical name
  10.138 + * must begin with one of the strings <tt>"X-"</tt> or <tt>"x-"</tt>.
  10.139 + *
  10.140 + * <p> The IANA charset registry does change over time, and so the canonical
  10.141 + * name and the aliases of a particular charset may also change over time.  To
  10.142 + * ensure compatibility it is recommended that no alias ever be removed from a
  10.143 + * charset, and that if the canonical name of a charset is changed then its
  10.144 + * previous canonical name be made into an alias.
  10.145 + *
  10.146 + *
  10.147 + * <h4>Standard charsets</h4>
  10.148 + *
  10.149 + * <a name="standard">
  10.150 + *
  10.151 + * <p> Every implementation of the Java platform is required to support the
  10.152 + * following standard charsets.  Consult the release documentation for your
  10.153 + * implementation to see if any other charsets are supported.  The behavior
  10.154 + * of such optional charsets may differ between implementations.
  10.155 + *
  10.156 + * <blockquote><table width="80%" summary="Description of standard charsets">
  10.157 + * <tr><th><p align="left">Charset</p></th><th><p align="left">Description</p></th></tr>
  10.158 + * <tr><td valign=top><tt>US-ASCII</tt></td>
  10.159 + *     <td>Seven-bit ASCII, a.k.a. <tt>ISO646-US</tt>,
  10.160 + *         a.k.a. the Basic Latin block of the Unicode character set</td></tr>
  10.161 + * <tr><td valign=top><tt>ISO-8859-1&nbsp;&nbsp;</tt></td>
  10.162 + *     <td>ISO Latin Alphabet No. 1, a.k.a. <tt>ISO-LATIN-1</tt></td></tr>
  10.163 + * <tr><td valign=top><tt>UTF-8</tt></td>
  10.164 + *     <td>Eight-bit UCS Transformation Format</td></tr>
  10.165 + * <tr><td valign=top><tt>UTF-16BE</tt></td>
  10.166 + *     <td>Sixteen-bit UCS Transformation Format,
  10.167 + *         big-endian byte&nbsp;order</td></tr>
  10.168 + * <tr><td valign=top><tt>UTF-16LE</tt></td>
  10.169 + *     <td>Sixteen-bit UCS Transformation Format,
  10.170 + *         little-endian byte&nbsp;order</td></tr>
  10.171 + * <tr><td valign=top><tt>UTF-16</tt></td>
  10.172 + *     <td>Sixteen-bit UCS Transformation Format,
  10.173 + *         byte&nbsp;order identified by an optional byte-order mark</td></tr>
  10.174 + * </table></blockquote>
  10.175 + *
  10.176 + * <p> The <tt>UTF-8</tt> charset is specified by <a
  10.177 + * href="http://www.ietf.org/rfc/rfc2279.txt"><i>RFC&nbsp;2279</i></a>; the
  10.178 + * transformation format upon which it is based is specified in
  10.179 + * Amendment&nbsp;2 of ISO&nbsp;10646-1 and is also described in the <a
  10.180 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
  10.181 + * Standard</i></a>.
  10.182 + *
  10.183 + * <p> The <tt>UTF-16</tt> charsets are specified by <a
  10.184 + * href="http://www.ietf.org/rfc/rfc2781.txt"><i>RFC&nbsp;2781</i></a>; the
  10.185 + * transformation formats upon which they are based are specified in
  10.186 + * Amendment&nbsp;1 of ISO&nbsp;10646-1 and are also described in the <a
  10.187 + * href="http://www.unicode.org/unicode/standard/standard.html"><i>Unicode
  10.188 + * Standard</i></a>.
  10.189 + *
  10.190 + * <p> The <tt>UTF-16</tt> charsets use sixteen-bit quantities and are
  10.191 + * therefore sensitive to byte order.  In these encodings the byte order of a
  10.192 + * stream may be indicated by an initial <i>byte-order mark</i> represented by
  10.193 + * the Unicode character <tt>'&#92;uFEFF'</tt>.  Byte-order marks are handled
  10.194 + * as follows:
  10.195 + *
  10.196 + * <ul>
  10.197 + *
  10.198 + *   <li><p> When decoding, the <tt>UTF-16BE</tt> and <tt>UTF-16LE</tt>
  10.199 + *   charsets interpret the initial byte-order marks as a <small>ZERO-WIDTH
  10.200 + *   NON-BREAKING SPACE</small>; when encoding, they do not write
  10.201 + *   byte-order marks. </p></li>
  10.202 +
  10.203 + *
  10.204 + *   <li><p> When decoding, the <tt>UTF-16</tt> charset interprets the
  10.205 + *   byte-order mark at the beginning of the input stream to indicate the
  10.206 + *   byte-order of the stream but defaults to big-endian if there is no
  10.207 + *   byte-order mark; when encoding, it uses big-endian byte order and writes
  10.208 + *   a big-endian byte-order mark. </p></li>
  10.209 + *
  10.210 + * </ul>
  10.211 + *
  10.212 + * In any case, byte order marks occuring after the first element of an
  10.213 + * input sequence are not omitted since the same code is used to represent
  10.214 + * <small>ZERO-WIDTH NON-BREAKING SPACE</small>.
  10.215 + *
  10.216 + * <p> Every instance of the Java virtual machine has a default charset, which
  10.217 + * may or may not be one of the standard charsets.  The default charset is
  10.218 + * determined during virtual-machine startup and typically depends upon the
  10.219 + * locale and charset being used by the underlying operating system. </p>
  10.220 + *
  10.221 + * <p>The {@link StandardCharsets} class defines constants for each of the
  10.222 + * standard charsets.
  10.223 + *
  10.224 + * <h4>Terminology</h4>
  10.225 + *
  10.226 + * <p> The name of this class is taken from the terms used in
  10.227 + * <a href="http://www.ietf.org/rfc/rfc2278.txt"><i>RFC&nbsp;2278</i></a>.
  10.228 + * In that document a <i>charset</i> is defined as the combination of
  10.229 + * one or more coded character sets and a character-encoding scheme.
  10.230 + * (This definition is confusing; some other software systems define
  10.231 + * <i>charset</i> as a synonym for <i>coded character set</i>.)
  10.232 + *
  10.233 + * <p> A <i>coded character set</i> is a mapping between a set of abstract
  10.234 + * characters and a set of integers.  US-ASCII, ISO&nbsp;8859-1,
  10.235 + * JIS&nbsp;X&nbsp;0201, and Unicode are examples of coded character sets.
  10.236 + *
  10.237 + * <p> Some standards have defined a <i>character set</i> to be simply a
  10.238 + * set of abstract characters without an associated assigned numbering.
  10.239 + * An alphabet is an example of such a character set.  However, the subtle
  10.240 + * distinction between <i>character set</i> and <i>coded character set</i>
  10.241 + * is rarely used in practice; the former has become a short form for the
  10.242 + * latter, including in the Java API specification.
  10.243 + *
  10.244 + * <p> A <i>character-encoding scheme</i> is a mapping between one or more
  10.245 + * coded character sets and a set of octet (eight-bit byte) sequences.
  10.246 + * UTF-8, UTF-16, ISO&nbsp;2022, and EUC are examples of
  10.247 + * character-encoding schemes.  Encoding schemes are often associated with
  10.248 + * a particular coded character set; UTF-8, for example, is used only to
  10.249 + * encode Unicode.  Some schemes, however, are associated with multiple
  10.250 + * coded character sets; EUC, for example, can be used to encode
  10.251 + * characters in a variety of Asian coded character sets.
  10.252 + *
  10.253 + * <p> When a coded character set is used exclusively with a single
  10.254 + * character-encoding scheme then the corresponding charset is usually
  10.255 + * named for the coded character set; otherwise a charset is usually named
  10.256 + * for the encoding scheme and, possibly, the locale of the coded
  10.257 + * character sets that it supports.  Hence <tt>US-ASCII</tt> is both the
  10.258 + * name of a coded character set and of the charset that encodes it, while
  10.259 + * <tt>EUC-JP</tt> is the name of the charset that encodes the
  10.260 + * JIS&nbsp;X&nbsp;0201, JIS&nbsp;X&nbsp;0208, and JIS&nbsp;X&nbsp;0212
  10.261 + * coded character sets for the Japanese language.
  10.262 + *
  10.263 + * <p> The native character encoding of the Java programming language is
  10.264 + * UTF-16.  A charset in the Java platform therefore defines a mapping
  10.265 + * between sequences of sixteen-bit UTF-16 code units (that is, sequences
  10.266 + * of chars) and sequences of bytes. </p>
  10.267 + *
  10.268 + *
  10.269 + * @author Mark Reinhold
  10.270 + * @author JSR-51 Expert Group
  10.271 + * @since 1.4
  10.272 + *
  10.273 + * @see CharsetDecoder
  10.274 + * @see CharsetEncoder
  10.275 + * @see java.nio.charset.spi.CharsetProvider
  10.276 + * @see java.lang.Character
  10.277 + */
  10.278 +
  10.279 +public abstract class Charset
  10.280 +    implements Comparable<Charset>
  10.281 +{
  10.282 +
  10.283 +    /* -- Static methods -- */
  10.284 +
  10.285 +    private static volatile String bugLevel = null;
  10.286 +
  10.287 +    static boolean atBugLevel(String bl) {              // package-private
  10.288 +        String level = bugLevel;
  10.289 +        if (level == null) {
  10.290 +            if (!sun.misc.VM.isBooted())
  10.291 +                return false;
  10.292 +            bugLevel = level = AccessController.doPrivileged(
  10.293 +                new GetPropertyAction("sun.nio.cs.bugLevel", ""));
  10.294 +        }
  10.295 +        return level.equals(bl);
  10.296 +    }
  10.297 +
  10.298 +    /**
  10.299 +     * Checks that the given string is a legal charset name. </p>
  10.300 +     *
  10.301 +     * @param  s
  10.302 +     *         A purported charset name
  10.303 +     *
  10.304 +     * @throws  IllegalCharsetNameException
  10.305 +     *          If the given name is not a legal charset name
  10.306 +     */
  10.307 +    private static void checkName(String s) {
  10.308 +        int n = s.length();
  10.309 +        if (!atBugLevel("1.4")) {
  10.310 +            if (n == 0)
  10.311 +                throw new IllegalCharsetNameException(s);
  10.312 +        }
  10.313 +        for (int i = 0; i < n; i++) {
  10.314 +            char c = s.charAt(i);
  10.315 +            if (c >= 'A' && c <= 'Z') continue;
  10.316 +            if (c >= 'a' && c <= 'z') continue;
  10.317 +            if (c >= '0' && c <= '9') continue;
  10.318 +            if (c == '-' && i != 0) continue;
  10.319 +            if (c == '+' && i != 0) continue;
  10.320 +            if (c == ':' && i != 0) continue;
  10.321 +            if (c == '_' && i != 0) continue;
  10.322 +            if (c == '.' && i != 0) continue;
  10.323 +            throw new IllegalCharsetNameException(s);
  10.324 +        }
  10.325 +    }
  10.326 +
  10.327 +    /* The standard set of charsets */
  10.328 +    private static CharsetProvider standardProvider = new StandardCharsets();
  10.329 +
  10.330 +    // Cache of the most-recently-returned charsets,
  10.331 +    // along with the names that were used to find them
  10.332 +    //
  10.333 +    private static volatile Object[] cache1 = null; // "Level 1" cache
  10.334 +    private static volatile Object[] cache2 = null; // "Level 2" cache
  10.335 +
  10.336 +    private static void cache(String charsetName, Charset cs) {
  10.337 +        cache2 = cache1;
  10.338 +        cache1 = new Object[] { charsetName, cs };
  10.339 +    }
  10.340 +
  10.341 +    // Creates an iterator that walks over the available providers, ignoring
  10.342 +    // those whose lookup or instantiation causes a security exception to be
  10.343 +    // thrown.  Should be invoked with full privileges.
  10.344 +    //
  10.345 +    private static Iterator providers() {
  10.346 +        return new Iterator() {
  10.347 +
  10.348 +                ClassLoader cl = ClassLoader.getSystemClassLoader();
  10.349 +                ServiceLoader<CharsetProvider> sl =
  10.350 +                    ServiceLoader.load(CharsetProvider.class, cl);
  10.351 +                Iterator<CharsetProvider> i = sl.iterator();
  10.352 +
  10.353 +                Object next = null;
  10.354 +
  10.355 +                private boolean getNext() {
  10.356 +                    while (next == null) {
  10.357 +                        try {
  10.358 +                            if (!i.hasNext())
  10.359 +                                return false;
  10.360 +                            next = i.next();
  10.361 +                        } catch (ServiceConfigurationError sce) {
  10.362 +                            if (sce.getCause() instanceof SecurityException) {
  10.363 +                                // Ignore security exceptions
  10.364 +                                continue;
  10.365 +                            }
  10.366 +                            throw sce;
  10.367 +                        }
  10.368 +                    }
  10.369 +                    return true;
  10.370 +                }
  10.371 +
  10.372 +                public boolean hasNext() {
  10.373 +                    return getNext();
  10.374 +                }
  10.375 +
  10.376 +                public Object next() {
  10.377 +                    if (!getNext())
  10.378 +                        throw new NoSuchElementException();
  10.379 +                    Object n = next;
  10.380 +                    next = null;
  10.381 +                    return n;
  10.382 +                }
  10.383 +
  10.384 +                public void remove() {
  10.385 +                    throw new UnsupportedOperationException();
  10.386 +                }
  10.387 +
  10.388 +            };
  10.389 +    }
  10.390 +
  10.391 +    // Thread-local gate to prevent recursive provider lookups
  10.392 +    private static ThreadLocal<ThreadLocal> gate = new ThreadLocal<ThreadLocal>();
  10.393 +
  10.394 +    private static Charset lookupViaProviders(final String charsetName) {
  10.395 +
  10.396 +        // The runtime startup sequence looks up standard charsets as a
  10.397 +        // consequence of the VM's invocation of System.initializeSystemClass
  10.398 +        // in order to, e.g., set system properties and encode filenames.  At
  10.399 +        // that point the application class loader has not been initialized,
  10.400 +        // however, so we can't look for providers because doing so will cause
  10.401 +        // that loader to be prematurely initialized with incomplete
  10.402 +        // information.
  10.403 +        //
  10.404 +        if (!sun.misc.VM.isBooted())
  10.405 +            return null;
  10.406 +
  10.407 +        if (gate.get() != null)
  10.408 +            // Avoid recursive provider lookups
  10.409 +            return null;
  10.410 +        try {
  10.411 +            gate.set(gate);
  10.412 +
  10.413 +            return AccessController.doPrivileged(
  10.414 +                new PrivilegedAction<Charset>() {
  10.415 +                    public Charset run() {
  10.416 +                        for (Iterator i = providers(); i.hasNext();) {
  10.417 +                            CharsetProvider cp = (CharsetProvider)i.next();
  10.418 +                            Charset cs = cp.charsetForName(charsetName);
  10.419 +                            if (cs != null)
  10.420 +                                return cs;
  10.421 +                        }
  10.422 +                        return null;
  10.423 +                    }
  10.424 +                });
  10.425 +
  10.426 +        } finally {
  10.427 +            gate.set(null);
  10.428 +        }
  10.429 +    }
  10.430 +
  10.431 +    /* The extended set of charsets */
  10.432 +    private static Object extendedProviderLock = new Object();
  10.433 +    private static boolean extendedProviderProbed = false;
  10.434 +    private static CharsetProvider extendedProvider = null;
  10.435 +
  10.436 +    private static void probeExtendedProvider() {
  10.437 +        AccessController.doPrivileged(new PrivilegedAction<Object>() {
  10.438 +                public Object run() {
  10.439 +                    try {
  10.440 +                        Class epc
  10.441 +                            = Class.forName("sun.nio.cs.ext.ExtendedCharsets");
  10.442 +                        extendedProvider = (CharsetProvider)epc.newInstance();
  10.443 +                    } catch (ClassNotFoundException x) {
  10.444 +                        // Extended charsets not available
  10.445 +                        // (charsets.jar not present)
  10.446 +                    } catch (InstantiationException x) {
  10.447 +                        throw new Error(x);
  10.448 +                    } catch (IllegalAccessException x) {
  10.449 +                        throw new Error(x);
  10.450 +                    }
  10.451 +                    return null;
  10.452 +                }
  10.453 +            });
  10.454 +    }
  10.455 +
  10.456 +    private static Charset lookupExtendedCharset(String charsetName) {
  10.457 +        CharsetProvider ecp = null;
  10.458 +        synchronized (extendedProviderLock) {
  10.459 +            if (!extendedProviderProbed) {
  10.460 +                probeExtendedProvider();
  10.461 +                extendedProviderProbed = true;
  10.462 +            }
  10.463 +            ecp = extendedProvider;
  10.464 +        }
  10.465 +        return (ecp != null) ? ecp.charsetForName(charsetName) : null;
  10.466 +    }
  10.467 +
  10.468 +    private static Charset lookup(String charsetName) {
  10.469 +        if (charsetName == null)
  10.470 +            throw new IllegalArgumentException("Null charset name");
  10.471 +
  10.472 +        Object[] a;
  10.473 +        if ((a = cache1) != null && charsetName.equals(a[0]))
  10.474 +            return (Charset)a[1];
  10.475 +        // We expect most programs to use one Charset repeatedly.
  10.476 +        // We convey a hint to this effect to the VM by putting the
  10.477 +        // level 1 cache miss code in a separate method.
  10.478 +        return lookup2(charsetName);
  10.479 +    }
  10.480 +
  10.481 +    private static Charset lookup2(String charsetName) {
  10.482 +        Object[] a;
  10.483 +        if ((a = cache2) != null && charsetName.equals(a[0])) {
  10.484 +            cache2 = cache1;
  10.485 +            cache1 = a;
  10.486 +            return (Charset)a[1];
  10.487 +        }
  10.488 +
  10.489 +        Charset cs;
  10.490 +        if ((cs = standardProvider.charsetForName(charsetName)) != null ||
  10.491 +            (cs = lookupExtendedCharset(charsetName))           != null ||
  10.492 +            (cs = lookupViaProviders(charsetName))              != null)
  10.493 +        {
  10.494 +            cache(charsetName, cs);
  10.495 +            return cs;
  10.496 +        }
  10.497 +
  10.498 +        /* Only need to check the name if we didn't find a charset for it */
  10.499 +        checkName(charsetName);
  10.500 +        return null;
  10.501 +    }
  10.502 +
  10.503 +    /**
  10.504 +     * Tells whether the named charset is supported. </p>
  10.505 +     *
  10.506 +     * @param  charsetName
  10.507 +     *         The name of the requested charset; may be either
  10.508 +     *         a canonical name or an alias
  10.509 +     *
  10.510 +     * @return  <tt>true</tt> if, and only if, support for the named charset
  10.511 +     *          is available in the current Java virtual machine
  10.512 +     *
  10.513 +     * @throws IllegalCharsetNameException
  10.514 +     *         If the given charset name is illegal
  10.515 +     *
  10.516 +     * @throws  IllegalArgumentException
  10.517 +     *          If the given <tt>charsetName</tt> is null
  10.518 +     */
  10.519 +    public static boolean isSupported(String charsetName) {
  10.520 +        return (lookup(charsetName) != null);
  10.521 +    }
  10.522 +
  10.523 +    /**
  10.524 +     * Returns a charset object for the named charset. </p>
  10.525 +     *
  10.526 +     * @param  charsetName
  10.527 +     *         The name of the requested charset; may be either
  10.528 +     *         a canonical name or an alias
  10.529 +     *
  10.530 +     * @return  A charset object for the named charset
  10.531 +     *
  10.532 +     * @throws  IllegalCharsetNameException
  10.533 +     *          If the given charset name is illegal
  10.534 +     *
  10.535 +     * @throws  IllegalArgumentException
  10.536 +     *          If the given <tt>charsetName</tt> is null
  10.537 +     *
  10.538 +     * @throws  UnsupportedCharsetException
  10.539 +     *          If no support for the named charset is available
  10.540 +     *          in this instance of the Java virtual machine
  10.541 +     */
  10.542 +    public static Charset forName(String charsetName) {
  10.543 +        Charset cs = lookup(charsetName);
  10.544 +        if (cs != null)
  10.545 +            return cs;
  10.546 +        throw new UnsupportedCharsetException(charsetName);
  10.547 +    }
  10.548 +
  10.549 +    // Fold charsets from the given iterator into the given map, ignoring
  10.550 +    // charsets whose names already have entries in the map.
  10.551 +    //
  10.552 +    private static void put(Iterator<Charset> i, Map<String,Charset> m) {
  10.553 +        while (i.hasNext()) {
  10.554 +            Charset cs = i.next();
  10.555 +            if (!m.containsKey(cs.name()))
  10.556 +                m.put(cs.name(), cs);
  10.557 +        }
  10.558 +    }
  10.559 +
  10.560 +    /**
  10.561 +     * Constructs a sorted map from canonical charset names to charset objects.
  10.562 +     *
  10.563 +     * <p> The map returned by this method will have one entry for each charset
  10.564 +     * for which support is available in the current Java virtual machine.  If
  10.565 +     * two or more supported charsets have the same canonical name then the
  10.566 +     * resulting map will contain just one of them; which one it will contain
  10.567 +     * is not specified. </p>
  10.568 +     *
  10.569 +     * <p> The invocation of this method, and the subsequent use of the
  10.570 +     * resulting map, may cause time-consuming disk or network I/O operations
  10.571 +     * to occur.  This method is provided for applications that need to
  10.572 +     * enumerate all of the available charsets, for example to allow user
  10.573 +     * charset selection.  This method is not used by the {@link #forName
  10.574 +     * forName} method, which instead employs an efficient incremental lookup
  10.575 +     * algorithm.
  10.576 +     *
  10.577 +     * <p> This method may return different results at different times if new
  10.578 +     * charset providers are dynamically made available to the current Java
  10.579 +     * virtual machine.  In the absence of such changes, the charsets returned
  10.580 +     * by this method are exactly those that can be retrieved via the {@link
  10.581 +     * #forName forName} method.  </p>
  10.582 +     *
  10.583 +     * @return An immutable, case-insensitive map from canonical charset names
  10.584 +     *         to charset objects
  10.585 +     */
  10.586 +    public static SortedMap<String,Charset> availableCharsets() {
  10.587 +        return AccessController.doPrivileged(
  10.588 +            new PrivilegedAction<SortedMap<String,Charset>>() {
  10.589 +                public SortedMap<String,Charset> run() {
  10.590 +                    TreeMap<String,Charset> m =
  10.591 +                        new TreeMap<String,Charset>(
  10.592 +                            ASCIICaseInsensitiveComparator.CASE_INSENSITIVE_ORDER);
  10.593 +                    put(standardProvider.charsets(), m);
  10.594 +                    for (Iterator i = providers(); i.hasNext();) {
  10.595 +                        CharsetProvider cp = (CharsetProvider)i.next();
  10.596 +                        put(cp.charsets(), m);
  10.597 +                    }
  10.598 +                    return Collections.unmodifiableSortedMap(m);
  10.599 +                }
  10.600 +            });
  10.601 +    }
  10.602 +
  10.603 +    private static volatile Charset defaultCharset;
  10.604 +
  10.605 +    /**
  10.606 +     * Returns the default charset of this Java virtual machine.
  10.607 +     *
  10.608 +     * <p> The default charset is determined during virtual-machine startup and
  10.609 +     * typically depends upon the locale and charset of the underlying
  10.610 +     * operating system.
  10.611 +     *
  10.612 +     * @return  A charset object for the default charset
  10.613 +     *
  10.614 +     * @since 1.5
  10.615 +     */
  10.616 +    public static Charset defaultCharset() {
  10.617 +        if (defaultCharset == null) {
  10.618 +            synchronized (Charset.class) {
  10.619 +                String csn = AccessController.doPrivileged(
  10.620 +                    new GetPropertyAction("file.encoding"));
  10.621 +                Charset cs = lookup(csn);
  10.622 +                if (cs != null)
  10.623 +                    defaultCharset = cs;
  10.624 +                else
  10.625 +                    defaultCharset = forName("UTF-8");
  10.626 +            }
  10.627 +        }
  10.628 +        return defaultCharset;
  10.629 +    }
  10.630 +
  10.631 +
  10.632 +    /* -- Instance fields and methods -- */
  10.633 +
  10.634 +    private final String name;          // tickles a bug in oldjavac
  10.635 +    private final String[] aliases;     // tickles a bug in oldjavac
  10.636 +    private Set<String> aliasSet = null;
  10.637 +
  10.638 +    /**
  10.639 +     * Initializes a new charset with the given canonical name and alias
  10.640 +     * set. </p>
  10.641 +     *
  10.642 +     * @param  canonicalName
  10.643 +     *         The canonical name of this charset
  10.644 +     *
  10.645 +     * @param  aliases
  10.646 +     *         An array of this charset's aliases, or null if it has no aliases
  10.647 +     *
  10.648 +     * @throws IllegalCharsetNameException
  10.649 +     *         If the canonical name or any of the aliases are illegal
  10.650 +     */
  10.651 +    protected Charset(String canonicalName, String[] aliases) {
  10.652 +        checkName(canonicalName);
  10.653 +        String[] as = (aliases == null) ? new String[0] : aliases;
  10.654 +        for (int i = 0; i < as.length; i++)
  10.655 +            checkName(as[i]);
  10.656 +        this.name = canonicalName;
  10.657 +        this.aliases = as;
  10.658 +    }
  10.659 +
  10.660 +    /**
  10.661 +     * Returns this charset's canonical name. </p>
  10.662 +     *
  10.663 +     * @return  The canonical name of this charset
  10.664 +     */
  10.665 +    public final String name() {
  10.666 +        return name;
  10.667 +    }
  10.668 +
  10.669 +    /**
  10.670 +     * Returns a set containing this charset's aliases. </p>
  10.671 +     *
  10.672 +     * @return  An immutable set of this charset's aliases
  10.673 +     */
  10.674 +    public final Set<String> aliases() {
  10.675 +        if (aliasSet != null)
  10.676 +            return aliasSet;
  10.677 +        int n = aliases.length;
  10.678 +        HashSet<String> hs = new HashSet<String>(n);
  10.679 +        for (int i = 0; i < n; i++)
  10.680 +            hs.add(aliases[i]);
  10.681 +        aliasSet = Collections.unmodifiableSet(hs);
  10.682 +        return aliasSet;
  10.683 +    }
  10.684 +
  10.685 +    /**
  10.686 +     * Returns this charset's human-readable name for the default locale.
  10.687 +     *
  10.688 +     * <p> The default implementation of this method simply returns this
  10.689 +     * charset's canonical name.  Concrete subclasses of this class may
  10.690 +     * override this method in order to provide a localized display name. </p>
  10.691 +     *
  10.692 +     * @return  The display name of this charset in the default locale
  10.693 +     */
  10.694 +    public String displayName() {
  10.695 +        return name;
  10.696 +    }
  10.697 +
  10.698 +    /**
  10.699 +     * Tells whether or not this charset is registered in the <a
  10.700 +     * href="http://www.iana.org/assignments/character-sets">IANA Charset
  10.701 +     * Registry</a>.  </p>
  10.702 +     *
  10.703 +     * @return  <tt>true</tt> if, and only if, this charset is known by its
  10.704 +     *          implementor to be registered with the IANA
  10.705 +     */
  10.706 +    public final boolean isRegistered() {
  10.707 +        return !name.startsWith("X-") && !name.startsWith("x-");
  10.708 +    }
  10.709 +
  10.710 +    /**
  10.711 +     * Returns this charset's human-readable name for the given locale.
  10.712 +     *
  10.713 +     * <p> The default implementation of this method simply returns this
  10.714 +     * charset's canonical name.  Concrete subclasses of this class may
  10.715 +     * override this method in order to provide a localized display name. </p>
  10.716 +     *
  10.717 +     * @param  locale
  10.718 +     *         The locale for which the display name is to be retrieved
  10.719 +     *
  10.720 +     * @return  The display name of this charset in the given locale
  10.721 +     */
  10.722 +    public String displayName(Locale locale) {
  10.723 +        return name;
  10.724 +    }
  10.725 +
  10.726 +    /**
  10.727 +     * Tells whether or not this charset contains the given charset.
  10.728 +     *
  10.729 +     * <p> A charset <i>C</i> is said to <i>contain</i> a charset <i>D</i> if,
  10.730 +     * and only if, every character representable in <i>D</i> is also
  10.731 +     * representable in <i>C</i>.  If this relationship holds then it is
  10.732 +     * guaranteed that every string that can be encoded in <i>D</i> can also be
  10.733 +     * encoded in <i>C</i> without performing any replacements.
  10.734 +     *
  10.735 +     * <p> That <i>C</i> contains <i>D</i> does not imply that each character
  10.736 +     * representable in <i>C</i> by a particular byte sequence is represented
  10.737 +     * in <i>D</i> by the same byte sequence, although sometimes this is the
  10.738 +     * case.
  10.739 +     *
  10.740 +     * <p> Every charset contains itself.
  10.741 +     *
  10.742 +     * <p> This method computes an approximation of the containment relation:
  10.743 +     * If it returns <tt>true</tt> then the given charset is known to be
  10.744 +     * contained by this charset; if it returns <tt>false</tt>, however, then
  10.745 +     * it is not necessarily the case that the given charset is not contained
  10.746 +     * in this charset.
  10.747 +     *
  10.748 +     * @return  <tt>true</tt> if the given charset is contained in this charset
  10.749 +     */
  10.750 +    public abstract boolean contains(Charset cs);
  10.751 +
  10.752 +    /**
  10.753 +     * Constructs a new decoder for this charset. </p>
  10.754 +     *
  10.755 +     * @return  A new decoder for this charset
  10.756 +     */
  10.757 +    public abstract CharsetDecoder newDecoder();
  10.758 +
  10.759 +    /**
  10.760 +     * Constructs a new encoder for this charset. </p>
  10.761 +     *
  10.762 +     * @return  A new encoder for this charset
  10.763 +     *
  10.764 +     * @throws  UnsupportedOperationException
  10.765 +     *          If this charset does not support encoding
  10.766 +     */
  10.767 +    public abstract CharsetEncoder newEncoder();
  10.768 +
  10.769 +    /**
  10.770 +     * Tells whether or not this charset supports encoding.
  10.771 +     *
  10.772 +     * <p> Nearly all charsets support encoding.  The primary exceptions are
  10.773 +     * special-purpose <i>auto-detect</i> charsets whose decoders can determine
  10.774 +     * which of several possible encoding schemes is in use by examining the
  10.775 +     * input byte sequence.  Such charsets do not support encoding because
  10.776 +     * there is no way to determine which encoding should be used on output.
  10.777 +     * Implementations of such charsets should override this method to return
  10.778 +     * <tt>false</tt>. </p>
  10.779 +     *
  10.780 +     * @return  <tt>true</tt> if, and only if, this charset supports encoding
  10.781 +     */
  10.782 +    public boolean canEncode() {
  10.783 +        return true;
  10.784 +    }
  10.785 +
  10.786 +    /**
  10.787 +     * Convenience method that decodes bytes in this charset into Unicode
  10.788 +     * characters.
  10.789 +     *
  10.790 +     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
  10.791 +     * same result as the expression
  10.792 +     *
  10.793 +     * <pre>
  10.794 +     *     cs.newDecoder()
  10.795 +     *       .onMalformedInput(CodingErrorAction.REPLACE)
  10.796 +     *       .onUnmappableCharacter(CodingErrorAction.REPLACE)
  10.797 +     *       .decode(bb); </pre>
  10.798 +     *
  10.799 +     * except that it is potentially more efficient because it can cache
  10.800 +     * decoders between successive invocations.
  10.801 +     *
  10.802 +     * <p> This method always replaces malformed-input and unmappable-character
  10.803 +     * sequences with this charset's default replacement byte array.  In order
  10.804 +     * to detect such sequences, use the {@link
  10.805 +     * CharsetDecoder#decode(java.nio.ByteBuffer)} method directly.  </p>
  10.806 +     *
  10.807 +     * @param  bb  The byte buffer to be decoded
  10.808 +     *
  10.809 +     * @return  A char buffer containing the decoded characters
  10.810 +     */
  10.811 +    public final CharBuffer decode(ByteBuffer bb) {
  10.812 +        try {
  10.813 +            return ThreadLocalCoders.decoderFor(this)
  10.814 +                .onMalformedInput(CodingErrorAction.REPLACE)
  10.815 +                .onUnmappableCharacter(CodingErrorAction.REPLACE)
  10.816 +                .decode(bb);
  10.817 +        } catch (CharacterCodingException x) {
  10.818 +            throw new Error(x);         // Can't happen
  10.819 +        }
  10.820 +    }
  10.821 +
  10.822 +    /**
  10.823 +     * Convenience method that encodes Unicode characters into bytes in this
  10.824 +     * charset.
  10.825 +     *
  10.826 +     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
  10.827 +     * same result as the expression
  10.828 +     *
  10.829 +     * <pre>
  10.830 +     *     cs.newEncoder()
  10.831 +     *       .onMalformedInput(CodingErrorAction.REPLACE)
  10.832 +     *       .onUnmappableCharacter(CodingErrorAction.REPLACE)
  10.833 +     *       .encode(bb); </pre>
  10.834 +     *
  10.835 +     * except that it is potentially more efficient because it can cache
  10.836 +     * encoders between successive invocations.
  10.837 +     *
  10.838 +     * <p> This method always replaces malformed-input and unmappable-character
  10.839 +     * sequences with this charset's default replacement string.  In order to
  10.840 +     * detect such sequences, use the {@link
  10.841 +     * CharsetEncoder#encode(java.nio.CharBuffer)} method directly.  </p>
  10.842 +     *
  10.843 +     * @param  cb  The char buffer to be encoded
  10.844 +     *
  10.845 +     * @return  A byte buffer containing the encoded characters
  10.846 +     */
  10.847 +    public final ByteBuffer encode(CharBuffer cb) {
  10.848 +        try {
  10.849 +            return ThreadLocalCoders.encoderFor(this)
  10.850 +                .onMalformedInput(CodingErrorAction.REPLACE)
  10.851 +                .onUnmappableCharacter(CodingErrorAction.REPLACE)
  10.852 +                .encode(cb);
  10.853 +        } catch (CharacterCodingException x) {
  10.854 +            throw new Error(x);         // Can't happen
  10.855 +        }
  10.856 +    }
  10.857 +
  10.858 +    /**
  10.859 +     * Convenience method that encodes a string into bytes in this charset.
  10.860 +     *
  10.861 +     * <p> An invocation of this method upon a charset <tt>cs</tt> returns the
  10.862 +     * same result as the expression
  10.863 +     *
  10.864 +     * <pre>
  10.865 +     *     cs.encode(CharBuffer.wrap(s)); </pre>
  10.866 +     *
  10.867 +     * @param  str  The string to be encoded
  10.868 +     *
  10.869 +     * @return  A byte buffer containing the encoded characters
  10.870 +     */
  10.871 +    public final ByteBuffer encode(String str) {
  10.872 +        return encode(CharBuffer.wrap(str));
  10.873 +    }
  10.874 +
  10.875 +    /**
  10.876 +     * Compares this charset to another.
  10.877 +     *
  10.878 +     * <p> Charsets are ordered by their canonical names, without regard to
  10.879 +     * case. </p>
  10.880 +     *
  10.881 +     * @param  that
  10.882 +     *         The charset to which this charset is to be compared
  10.883 +     *
  10.884 +     * @return A negative integer, zero, or a positive integer as this charset
  10.885 +     *         is less than, equal to, or greater than the specified charset
  10.886 +     */
  10.887 +    public final int compareTo(Charset that) {
  10.888 +        return (name().compareToIgnoreCase(that.name()));
  10.889 +    }
  10.890 +
  10.891 +    /**
  10.892 +     * Computes a hashcode for this charset. </p>
  10.893 +     *
  10.894 +     * @return  An integer hashcode
  10.895 +     */
  10.896 +    public final int hashCode() {
  10.897 +        return name().hashCode();
  10.898 +    }
  10.899 +
  10.900 +    /**
  10.901 +     * Tells whether or not this object is equal to another.
  10.902 +     *
  10.903 +     * <p> Two charsets are equal if, and only if, they have the same canonical
  10.904 +     * names.  A charset is never equal to any other type of object.  </p>
  10.905 +     *
  10.906 +     * @return  <tt>true</tt> if, and only if, this charset is equal to the
  10.907 +     *          given object
  10.908 +     */
  10.909 +    public final boolean equals(Object ob) {
  10.910 +        if (!(ob instanceof Charset))
  10.911 +            return false;
  10.912 +        if (this == ob)
  10.913 +            return true;
  10.914 +        return name.equals(((Charset)ob).name());
  10.915 +    }
  10.916 +
  10.917 +    /**
  10.918 +     * Returns a string describing this charset. </p>
  10.919 +     *
  10.920 +     * @return  A string describing this charset
  10.921 +     */
  10.922 +    public final String toString() {
  10.923 +        return name();
  10.924 +    }
  10.925 +
  10.926 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetDecoder.java	Thu Oct 03 15:40:35 2013 +0200
    11.3 @@ -0,0 +1,972 @@
    11.4 +/*
    11.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
    11.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    11.7 + *
    11.8 + *
    11.9 + *
   11.10 + *
   11.11 + *
   11.12 + *
   11.13 + *
   11.14 + *
   11.15 + *
   11.16 + *
   11.17 + *
   11.18 + *
   11.19 + *
   11.20 + *
   11.21 + *
   11.22 + *
   11.23 + *
   11.24 + *
   11.25 + *
   11.26 + *
   11.27 + */
   11.28 +
   11.29 +// -- This file was mechanically generated: Do not edit! -- //
   11.30 +
   11.31 +package java.nio.charset;
   11.32 +
   11.33 +import java.nio.Buffer;
   11.34 +import java.nio.ByteBuffer;
   11.35 +import java.nio.CharBuffer;
   11.36 +import java.nio.BufferOverflowException;
   11.37 +import java.nio.BufferUnderflowException;
   11.38 +import java.lang.ref.WeakReference;
   11.39 +import java.nio.charset.CoderMalfunctionError;                  // javadoc
   11.40 +
   11.41 +
   11.42 +/**
   11.43 + * An engine that can transform a sequence of bytes in a specific charset into a sequence of
   11.44 + * sixteen-bit Unicode characters.
   11.45 + *
   11.46 + * <a name="steps">
   11.47 + *
   11.48 + * <p> The input byte sequence is provided in a byte buffer or a series
   11.49 + * of such buffers.  The output character sequence is written to a character buffer
   11.50 + * or a series of such buffers.  A decoder should always be used by making
   11.51 + * the following sequence of method invocations, hereinafter referred to as a
   11.52 + * <i>decoding operation</i>:
   11.53 + *
   11.54 + * <ol>
   11.55 + *
   11.56 + *   <li><p> Reset the decoder via the {@link #reset reset} method, unless it
   11.57 + *   has not been used before; </p></li>
   11.58 + *
   11.59 + *   <li><p> Invoke the {@link #decode decode} method zero or more times, as
   11.60 + *   long as additional input may be available, passing <tt>false</tt> for the
   11.61 + *   <tt>endOfInput</tt> argument and filling the input buffer and flushing the
   11.62 + *   output buffer between invocations; </p></li>
   11.63 + *
   11.64 + *   <li><p> Invoke the {@link #decode decode} method one final time, passing
   11.65 + *   <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
   11.66 + *
   11.67 + *   <li><p> Invoke the {@link #flush flush} method so that the decoder can
   11.68 + *   flush any internal state to the output buffer. </p></li>
   11.69 + *
   11.70 + * </ol>
   11.71 + *
   11.72 + * Each invocation of the {@link #decode decode} method will decode as many
   11.73 + * bytes as possible from the input buffer, writing the resulting characters
   11.74 + * to the output buffer.  The {@link #decode decode} method returns when more
   11.75 + * input is required, when there is not enough room in the output buffer, or
   11.76 + * when a decoding error has occurred.  In each case a {@link CoderResult}
   11.77 + * object is returned to describe the reason for termination.  An invoker can
   11.78 + * examine this object and fill the input buffer, flush the output buffer, or
   11.79 + * attempt to recover from a decoding error, as appropriate, and try again.
   11.80 + *
   11.81 + * <a name="ce">
   11.82 + *
   11.83 + * <p> There are two general types of decoding errors.  If the input byte
   11.84 + * sequence is not legal for this charset then the input is considered <i>malformed</i>.  If
   11.85 + * the input byte sequence is legal but cannot be mapped to a valid
   11.86 + * Unicode character then an <i>unmappable character</i> has been encountered.
   11.87 + *
   11.88 + * <a name="cae">
   11.89 + *
   11.90 + * <p> How a decoding error is handled depends upon the action requested for
   11.91 + * that type of error, which is described by an instance of the {@link
   11.92 + * CodingErrorAction} class.  The possible error actions are to {@link
   11.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
   11.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
   11.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
   11.96 + * </code>replace<code>} the erroneous input with the current value of the
   11.97 + * replacement string.  The replacement
   11.98 + *
   11.99 +
  11.100 +
  11.101 +
  11.102 +
  11.103 +
  11.104 + * has the initial value <tt>"&#92;uFFFD"</tt>;
  11.105 +
  11.106 + *
  11.107 + * its value may be changed via the {@link #replaceWith(java.lang.String)
  11.108 + * replaceWith} method.
  11.109 + *
  11.110 + * <p> The default action for malformed-input and unmappable-character errors
  11.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them.  The
  11.112 + * malformed-input error action may be changed via the {@link
  11.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
  11.114 + * unmappable-character action may be changed via the {@link
  11.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
  11.116 + *
  11.117 + * <p> This class is designed to handle many of the details of the decoding
  11.118 + * process, including the implementation of error actions.  A decoder for a
  11.119 + * specific charset, which is a concrete subclass of this class, need only
  11.120 + * implement the abstract {@link #decodeLoop decodeLoop} method, which
  11.121 + * encapsulates the basic decoding loop.  A subclass that maintains internal
  11.122 + * state should, additionally, override the {@link #implFlush implFlush} and
  11.123 + * {@link #implReset implReset} methods.
  11.124 + *
  11.125 + * <p> Instances of this class are not safe for use by multiple concurrent
  11.126 + * threads.  </p>
  11.127 + *
  11.128 + *
  11.129 + * @author Mark Reinhold
  11.130 + * @author JSR-51 Expert Group
  11.131 + * @since 1.4
  11.132 + *
  11.133 + * @see ByteBuffer
  11.134 + * @see CharBuffer
  11.135 + * @see Charset
  11.136 + * @see CharsetEncoder
  11.137 + */
  11.138 +
  11.139 +public abstract class CharsetDecoder {
  11.140 +
  11.141 +    private final Charset charset;
  11.142 +    private final float averageCharsPerByte;
  11.143 +    private final float maxCharsPerByte;
  11.144 +
  11.145 +    private String replacement;
  11.146 +    private CodingErrorAction malformedInputAction
  11.147 +        = CodingErrorAction.REPORT;
  11.148 +    private CodingErrorAction unmappableCharacterAction
  11.149 +        = CodingErrorAction.REPORT;
  11.150 +
  11.151 +    // Internal states
  11.152 +    //
  11.153 +    private static final int ST_RESET   = 0;
  11.154 +    private static final int ST_CODING  = 1;
  11.155 +    private static final int ST_END     = 2;
  11.156 +    private static final int ST_FLUSHED = 3;
  11.157 +
  11.158 +    private int state = ST_RESET;
  11.159 +
  11.160 +    private static String stateNames[]
  11.161 +        = { "RESET", "CODING", "CODING_END", "FLUSHED" };
  11.162 +
  11.163 +
  11.164 +    /**
  11.165 +     * Initializes a new decoder.  The new decoder will have the given
  11.166 +     * chars-per-byte and replacement values. </p>
  11.167 +     *
  11.168 +     * @param  averageCharsPerByte
  11.169 +     *         A positive float value indicating the expected number of
  11.170 +     *         characters that will be produced for each input byte
  11.171 +     *
  11.172 +     * @param  maxCharsPerByte
  11.173 +     *         A positive float value indicating the maximum number of
  11.174 +     *         characters that will be produced for each input byte
  11.175 +     *
  11.176 +     * @param  replacement
  11.177 +     *         The initial replacement; must not be <tt>null</tt>, must have
  11.178 +     *         non-zero length, must not be longer than maxCharsPerByte,
  11.179 +     *         and must be {@link #isLegalReplacement </code>legal<code>}
  11.180 +     *
  11.181 +     * @throws  IllegalArgumentException
  11.182 +     *          If the preconditions on the parameters do not hold
  11.183 +     */
  11.184 +    private
  11.185 +    CharsetDecoder(Charset cs,
  11.186 +                   float averageCharsPerByte,
  11.187 +                   float maxCharsPerByte,
  11.188 +                   String replacement)
  11.189 +    {
  11.190 +        this.charset = cs;
  11.191 +        if (averageCharsPerByte <= 0.0f)
  11.192 +            throw new IllegalArgumentException("Non-positive "
  11.193 +                                               + "averageCharsPerByte");
  11.194 +        if (maxCharsPerByte <= 0.0f)
  11.195 +            throw new IllegalArgumentException("Non-positive "
  11.196 +                                               + "maxCharsPerByte");
  11.197 +        if (!Charset.atBugLevel("1.4")) {
  11.198 +            if (averageCharsPerByte > maxCharsPerByte)
  11.199 +                throw new IllegalArgumentException("averageCharsPerByte"
  11.200 +                                                   + " exceeds "
  11.201 +                                                   + "maxCharsPerByte");
  11.202 +        }
  11.203 +        this.replacement = replacement;
  11.204 +        this.averageCharsPerByte = averageCharsPerByte;
  11.205 +        this.maxCharsPerByte = maxCharsPerByte;
  11.206 +        replaceWith(replacement);
  11.207 +    }
  11.208 +
  11.209 +    /**
  11.210 +     * Initializes a new decoder.  The new decoder will have the given
  11.211 +     * chars-per-byte values and its replacement will be the
  11.212 +     * string <tt>"&#92;uFFFD"</tt>. </p>
  11.213 +     *
  11.214 +     * @param  averageCharsPerByte
  11.215 +     *         A positive float value indicating the expected number of
  11.216 +     *         characters that will be produced for each input byte
  11.217 +     *
  11.218 +     * @param  maxCharsPerByte
  11.219 +     *         A positive float value indicating the maximum number of
  11.220 +     *         characters that will be produced for each input byte
  11.221 +     *
  11.222 +     * @throws  IllegalArgumentException
  11.223 +     *          If the preconditions on the parameters do not hold
  11.224 +     */
  11.225 +    protected CharsetDecoder(Charset cs,
  11.226 +                             float averageCharsPerByte,
  11.227 +                             float maxCharsPerByte)
  11.228 +    {
  11.229 +        this(cs,
  11.230 +             averageCharsPerByte, maxCharsPerByte,
  11.231 +             "\uFFFD");
  11.232 +    }
  11.233 +
  11.234 +    /**
  11.235 +     * Returns the charset that created this decoder.  </p>
  11.236 +     *
  11.237 +     * @return  This decoder's charset
  11.238 +     */
  11.239 +    public final Charset charset() {
  11.240 +        return charset;
  11.241 +    }
  11.242 +
  11.243 +    /**
  11.244 +     * Returns this decoder's replacement value. </p>
  11.245 +     *
  11.246 +     * @return  This decoder's current replacement,
  11.247 +     *          which is never <tt>null</tt> and is never empty
  11.248 +     */
  11.249 +    public final String replacement() {
  11.250 +        return replacement;
  11.251 +    }
  11.252 +
  11.253 +    /**
  11.254 +     * Changes this decoder's replacement value.
  11.255 +     *
  11.256 +     * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
  11.257 +     * method, passing the new replacement, after checking that the new
  11.258 +     * replacement is acceptable.  </p>
  11.259 +     *
  11.260 +     * @param  newReplacement
  11.261 +     *
  11.262 +
  11.263 +     *         The new replacement; must not be <tt>null</tt>
  11.264 +     *         and must have non-zero length
  11.265 +
  11.266 +
  11.267 +
  11.268 +
  11.269 +
  11.270 +
  11.271 +
  11.272 +     *
  11.273 +     * @return  This decoder
  11.274 +     *
  11.275 +     * @throws  IllegalArgumentException
  11.276 +     *          If the preconditions on the parameter do not hold
  11.277 +     */
  11.278 +    public final CharsetDecoder replaceWith(String newReplacement) {
  11.279 +        if (newReplacement == null)
  11.280 +            throw new IllegalArgumentException("Null replacement");
  11.281 +        int len = newReplacement.length();
  11.282 +        if (len == 0)
  11.283 +            throw new IllegalArgumentException("Empty replacement");
  11.284 +        if (len > maxCharsPerByte)
  11.285 +            throw new IllegalArgumentException("Replacement too long");
  11.286 +
  11.287 +
  11.288 +
  11.289 +
  11.290 +        this.replacement = newReplacement;
  11.291 +        implReplaceWith(newReplacement);
  11.292 +        return this;
  11.293 +    }
  11.294 +
  11.295 +    /**
  11.296 +     * Reports a change to this decoder's replacement value.
  11.297 +     *
  11.298 +     * <p> The default implementation of this method does nothing.  This method
  11.299 +     * should be overridden by decoders that require notification of changes to
  11.300 +     * the replacement.  </p>
  11.301 +     *
  11.302 +     * @param  newReplacement
  11.303 +     */
  11.304 +    protected void implReplaceWith(String newReplacement) {
  11.305 +    }
  11.306 +
  11.307 +
  11.308 +
  11.309 +
  11.310 +
  11.311 +
  11.312 +
  11.313 +
  11.314 +
  11.315 +
  11.316 +
  11.317 +
  11.318 +
  11.319 +
  11.320 +
  11.321 +
  11.322 +
  11.323 +
  11.324 +
  11.325 +
  11.326 +
  11.327 +
  11.328 +
  11.329 +
  11.330 +
  11.331 +
  11.332 +
  11.333 +
  11.334 +
  11.335 +
  11.336 +
  11.337 +
  11.338 +
  11.339 +
  11.340 +
  11.341 +
  11.342 +
  11.343 +
  11.344 +
  11.345 +
  11.346 +
  11.347 +    /**
  11.348 +     * Returns this decoder's current action for malformed-input errors.  </p>
  11.349 +     *
  11.350 +     * @return The current malformed-input action, which is never <tt>null</tt>
  11.351 +     */
  11.352 +    public CodingErrorAction malformedInputAction() {
  11.353 +        return malformedInputAction;
  11.354 +    }
  11.355 +
  11.356 +    /**
  11.357 +     * Changes this decoder's action for malformed-input errors.  </p>
  11.358 +     *
  11.359 +     * <p> This method invokes the {@link #implOnMalformedInput
  11.360 +     * implOnMalformedInput} method, passing the new action.  </p>
  11.361 +     *
  11.362 +     * @param  newAction  The new action; must not be <tt>null</tt>
  11.363 +     *
  11.364 +     * @return  This decoder
  11.365 +     *
  11.366 +     * @throws IllegalArgumentException
  11.367 +     *         If the precondition on the parameter does not hold
  11.368 +     */
  11.369 +    public final CharsetDecoder onMalformedInput(CodingErrorAction newAction) {
  11.370 +        if (newAction == null)
  11.371 +            throw new IllegalArgumentException("Null action");
  11.372 +        malformedInputAction = newAction;
  11.373 +        implOnMalformedInput(newAction);
  11.374 +        return this;
  11.375 +    }
  11.376 +
  11.377 +    /**
  11.378 +     * Reports a change to this decoder's malformed-input action.
  11.379 +     *
  11.380 +     * <p> The default implementation of this method does nothing.  This method
  11.381 +     * should be overridden by decoders that require notification of changes to
  11.382 +     * the malformed-input action.  </p>
  11.383 +     */
  11.384 +    protected void implOnMalformedInput(CodingErrorAction newAction) { }
  11.385 +
  11.386 +    /**
  11.387 +     * Returns this decoder's current action for unmappable-character errors.
  11.388 +     * </p>
  11.389 +     *
  11.390 +     * @return The current unmappable-character action, which is never
  11.391 +     *         <tt>null</tt>
  11.392 +     */
  11.393 +    public CodingErrorAction unmappableCharacterAction() {
  11.394 +        return unmappableCharacterAction;
  11.395 +    }
  11.396 +
  11.397 +    /**
  11.398 +     * Changes this decoder's action for unmappable-character errors.
  11.399 +     *
  11.400 +     * <p> This method invokes the {@link #implOnUnmappableCharacter
  11.401 +     * implOnUnmappableCharacter} method, passing the new action.  </p>
  11.402 +     *
  11.403 +     * @param  newAction  The new action; must not be <tt>null</tt>
  11.404 +     *
  11.405 +     * @return  This decoder
  11.406 +     *
  11.407 +     * @throws IllegalArgumentException
  11.408 +     *         If the precondition on the parameter does not hold
  11.409 +     */
  11.410 +    public final CharsetDecoder onUnmappableCharacter(CodingErrorAction
  11.411 +                                                      newAction)
  11.412 +    {
  11.413 +        if (newAction == null)
  11.414 +            throw new IllegalArgumentException("Null action");
  11.415 +        unmappableCharacterAction = newAction;
  11.416 +        implOnUnmappableCharacter(newAction);
  11.417 +        return this;
  11.418 +    }
  11.419 +
  11.420 +    /**
  11.421 +     * Reports a change to this decoder's unmappable-character action.
  11.422 +     *
  11.423 +     * <p> The default implementation of this method does nothing.  This method
  11.424 +     * should be overridden by decoders that require notification of changes to
  11.425 +     * the unmappable-character action.  </p>
  11.426 +     */
  11.427 +    protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
  11.428 +
  11.429 +    /**
  11.430 +     * Returns the average number of characters that will be produced for each
  11.431 +     * byte of input.  This heuristic value may be used to estimate the size
  11.432 +     * of the output buffer required for a given input sequence. </p>
  11.433 +     *
  11.434 +     * @return  The average number of characters produced
  11.435 +     *          per byte of input
  11.436 +     */
  11.437 +    public final float averageCharsPerByte() {
  11.438 +        return averageCharsPerByte;
  11.439 +    }
  11.440 +
  11.441 +    /**
  11.442 +     * Returns the maximum number of characters that will be produced for each
  11.443 +     * byte of input.  This value may be used to compute the worst-case size
  11.444 +     * of the output buffer required for a given input sequence. </p>
  11.445 +     *
  11.446 +     * @return  The maximum number of characters that will be produced per
  11.447 +     *          byte of input
  11.448 +     */
  11.449 +    public final float maxCharsPerByte() {
  11.450 +        return maxCharsPerByte;
  11.451 +    }
  11.452 +
  11.453 +    /**
  11.454 +     * Decodes as many bytes as possible from the given input buffer,
  11.455 +     * writing the results to the given output buffer.
  11.456 +     *
  11.457 +     * <p> The buffers are read from, and written to, starting at their current
  11.458 +     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
  11.459 +     * will be read and at most {@link Buffer#remaining out.remaining()}
  11.460 +     * characters will be written.  The buffers' positions will be advanced to
  11.461 +     * reflect the bytes read and the characters written, but their marks and
  11.462 +     * limits will not be modified.
  11.463 +     *
  11.464 +     * <p> In addition to reading bytes from the input buffer and writing
  11.465 +     * characters to the output buffer, this method returns a {@link CoderResult}
  11.466 +     * object to describe its reason for termination:
  11.467 +     *
  11.468 +     * <ul>
  11.469 +     *
  11.470 +     *   <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
  11.471 +     *   input buffer as possible has been decoded.  If there is no further
  11.472 +     *   input then the invoker can proceed to the next step of the
  11.473 +     *   <a href="#steps">decoding operation</a>.  Otherwise this method
  11.474 +     *   should be invoked again with further input.  </p></li>
  11.475 +     *
  11.476 +     *   <li><p> {@link CoderResult#OVERFLOW} indicates that there is
  11.477 +     *   insufficient space in the output buffer to decode any more bytes.
  11.478 +     *   This method should be invoked again with an output buffer that has
  11.479 +     *   more {@linkplain Buffer#remaining remaining} characters. This is
  11.480 +     *   typically done by draining any decoded characters from the output
  11.481 +     *   buffer.  </p></li>
  11.482 +     *
  11.483 +     *   <li><p> A {@link CoderResult#malformedForLength
  11.484 +     *   </code>malformed-input<code>} result indicates that a malformed-input
  11.485 +     *   error has been detected.  The malformed bytes begin at the input
  11.486 +     *   buffer's (possibly incremented) position; the number of malformed
  11.487 +     *   bytes may be determined by invoking the result object's {@link
  11.488 +     *   CoderResult#length() length} method.  This case applies only if the
  11.489 +     *   {@link #onMalformedInput </code>malformed action<code>} of this decoder
  11.490 +     *   is {@link CodingErrorAction#REPORT}; otherwise the malformed input
  11.491 +     *   will be ignored or replaced, as requested.  </p></li>
  11.492 +     *
  11.493 +     *   <li><p> An {@link CoderResult#unmappableForLength
  11.494 +     *   </code>unmappable-character<code>} result indicates that an
  11.495 +     *   unmappable-character error has been detected.  The bytes that
  11.496 +     *   decode the unmappable character begin at the input buffer's (possibly
  11.497 +     *   incremented) position; the number of such bytes may be determined
  11.498 +     *   by invoking the result object's {@link CoderResult#length() length}
  11.499 +     *   method.  This case applies only if the {@link #onUnmappableCharacter
  11.500 +     *   </code>unmappable action<code>} of this decoder is {@link
  11.501 +     *   CodingErrorAction#REPORT}; otherwise the unmappable character will be
  11.502 +     *   ignored or replaced, as requested.  </p></li>
  11.503 +     *
  11.504 +     * </ul>
  11.505 +     *
  11.506 +     * In any case, if this method is to be reinvoked in the same decoding
  11.507 +     * operation then care should be taken to preserve any bytes remaining
  11.508 +     * in the input buffer so that they are available to the next invocation.
  11.509 +     *
  11.510 +     * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
  11.511 +     * the invoker can provide further input beyond that contained in the given
  11.512 +     * input buffer.  If there is a possibility of providing additional input
  11.513 +     * then the invoker should pass <tt>false</tt> for this parameter; if there
  11.514 +     * is no possibility of providing further input then the invoker should
  11.515 +     * pass <tt>true</tt>.  It is not erroneous, and in fact it is quite
  11.516 +     * common, to pass <tt>false</tt> in one invocation and later discover that
  11.517 +     * no further input was actually available.  It is critical, however, that
  11.518 +     * the final invocation of this method in a sequence of invocations always
  11.519 +     * pass <tt>true</tt> so that any remaining undecoded input will be treated
  11.520 +     * as being malformed.
  11.521 +     *
  11.522 +     * <p> This method works by invoking the {@link #decodeLoop decodeLoop}
  11.523 +     * method, interpreting its results, handling error conditions, and
  11.524 +     * reinvoking it as necessary.  </p>
  11.525 +     *
  11.526 +     *
  11.527 +     * @param  in
  11.528 +     *         The input byte buffer
  11.529 +     *
  11.530 +     * @param  out
  11.531 +     *         The output character buffer
  11.532 +     *
  11.533 +     * @param  endOfInput
  11.534 +     *         <tt>true</tt> if, and only if, the invoker can provide no
  11.535 +     *         additional input bytes beyond those in the given buffer
  11.536 +     *
  11.537 +     * @return  A coder-result object describing the reason for termination
  11.538 +     *
  11.539 +     * @throws  IllegalStateException
  11.540 +     *          If a decoding operation is already in progress and the previous
  11.541 +     *          step was an invocation neither of the {@link #reset reset}
  11.542 +     *          method, nor of this method with a value of <tt>false</tt> for
  11.543 +     *          the <tt>endOfInput</tt> parameter, nor of this method with a
  11.544 +     *          value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
  11.545 +     *          but a return value indicating an incomplete decoding operation
  11.546 +     *
  11.547 +     * @throws  CoderMalfunctionError
  11.548 +     *          If an invocation of the decodeLoop method threw
  11.549 +     *          an unexpected exception
  11.550 +     */
  11.551 +    public final CoderResult decode(ByteBuffer in, CharBuffer out,
  11.552 +                                    boolean endOfInput)
  11.553 +    {
  11.554 +        int newState = endOfInput ? ST_END : ST_CODING;
  11.555 +        if ((state != ST_RESET) && (state != ST_CODING)
  11.556 +            && !(endOfInput && (state == ST_END)))
  11.557 +            throwIllegalStateException(state, newState);
  11.558 +        state = newState;
  11.559 +
  11.560 +        for (;;) {
  11.561 +
  11.562 +            CoderResult cr;
  11.563 +            try {
  11.564 +                cr = decodeLoop(in, out);
  11.565 +            } catch (BufferUnderflowException x) {
  11.566 +                throw new CoderMalfunctionError(x);
  11.567 +            } catch (BufferOverflowException x) {
  11.568 +                throw new CoderMalfunctionError(x);
  11.569 +            }
  11.570 +
  11.571 +            if (cr.isOverflow())
  11.572 +                return cr;
  11.573 +
  11.574 +            if (cr.isUnderflow()) {
  11.575 +                if (endOfInput && in.hasRemaining()) {
  11.576 +                    cr = CoderResult.malformedForLength(in.remaining());
  11.577 +                    // Fall through to malformed-input case
  11.578 +                } else {
  11.579 +                    return cr;
  11.580 +                }
  11.581 +            }
  11.582 +
  11.583 +            CodingErrorAction action = null;
  11.584 +            if (cr.isMalformed())
  11.585 +                action = malformedInputAction;
  11.586 +            else if (cr.isUnmappable())
  11.587 +                action = unmappableCharacterAction;
  11.588 +            else
  11.589 +                assert false : cr.toString();
  11.590 +
  11.591 +            if (action == CodingErrorAction.REPORT)
  11.592 +                return cr;
  11.593 +
  11.594 +            if (action == CodingErrorAction.REPLACE) {
  11.595 +                if (out.remaining() < replacement.length())
  11.596 +                    return CoderResult.OVERFLOW;
  11.597 +                out.put(replacement);
  11.598 +            }
  11.599 +
  11.600 +            if ((action == CodingErrorAction.IGNORE)
  11.601 +                || (action == CodingErrorAction.REPLACE)) {
  11.602 +                // Skip erroneous input either way
  11.603 +                in.position(in.position() + cr.length());
  11.604 +                continue;
  11.605 +            }
  11.606 +
  11.607 +            assert false;
  11.608 +        }
  11.609 +
  11.610 +    }
  11.611 +
  11.612 +    /**
  11.613 +     * Flushes this decoder.
  11.614 +     *
  11.615 +     * <p> Some decoders maintain internal state and may need to write some
  11.616 +     * final characters to the output buffer once the overall input sequence has
  11.617 +     * been read.
  11.618 +     *
  11.619 +     * <p> Any additional output is written to the output buffer beginning at
  11.620 +     * its current position.  At most {@link Buffer#remaining out.remaining()}
  11.621 +     * characters will be written.  The buffer's position will be advanced
  11.622 +     * appropriately, but its mark and limit will not be modified.
  11.623 +     *
  11.624 +     * <p> If this method completes successfully then it returns {@link
  11.625 +     * CoderResult#UNDERFLOW}.  If there is insufficient room in the output
  11.626 +     * buffer then it returns {@link CoderResult#OVERFLOW}.  If this happens
  11.627 +     * then this method must be invoked again, with an output buffer that has
  11.628 +     * more room, in order to complete the current <a href="#steps">decoding
  11.629 +     * operation</a>.
  11.630 +     *
  11.631 +     * <p> If this decoder has already been flushed then invoking this method
  11.632 +     * has no effect.
  11.633 +     *
  11.634 +     * <p> This method invokes the {@link #implFlush implFlush} method to
  11.635 +     * perform the actual flushing operation.  </p>
  11.636 +     *
  11.637 +     * @param  out
  11.638 +     *         The output character buffer
  11.639 +     *
  11.640 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
  11.641 +     *          {@link CoderResult#OVERFLOW}
  11.642 +     *
  11.643 +     * @throws  IllegalStateException
  11.644 +     *          If the previous step of the current decoding operation was an
  11.645 +     *          invocation neither of the {@link #flush flush} method nor of
  11.646 +     *          the three-argument {@link
  11.647 +     *          #decode(ByteBuffer,CharBuffer,boolean) decode} method
  11.648 +     *          with a value of <tt>true</tt> for the <tt>endOfInput</tt>
  11.649 +     *          parameter
  11.650 +     */
  11.651 +    public final CoderResult flush(CharBuffer out) {
  11.652 +        if (state == ST_END) {
  11.653 +            CoderResult cr = implFlush(out);
  11.654 +            if (cr.isUnderflow())
  11.655 +                state = ST_FLUSHED;
  11.656 +            return cr;
  11.657 +        }
  11.658 +
  11.659 +        if (state != ST_FLUSHED)
  11.660 +            throwIllegalStateException(state, ST_FLUSHED);
  11.661 +
  11.662 +        return CoderResult.UNDERFLOW; // Already flushed
  11.663 +    }
  11.664 +
  11.665 +    /**
  11.666 +     * Flushes this decoder.
  11.667 +     *
  11.668 +     * <p> The default implementation of this method does nothing, and always
  11.669 +     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
  11.670 +     * by decoders that may need to write final characters to the output buffer
  11.671 +     * once the entire input sequence has been read. </p>
  11.672 +     *
  11.673 +     * @param  out
  11.674 +     *         The output character buffer
  11.675 +     *
  11.676 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
  11.677 +     *          {@link CoderResult#OVERFLOW}
  11.678 +     */
  11.679 +    protected CoderResult implFlush(CharBuffer out) {
  11.680 +        return CoderResult.UNDERFLOW;
  11.681 +    }
  11.682 +
  11.683 +    /**
  11.684 +     * Resets this decoder, clearing any internal state.
  11.685 +     *
  11.686 +     * <p> This method resets charset-independent state and also invokes the
  11.687 +     * {@link #implReset() implReset} method in order to perform any
  11.688 +     * charset-specific reset actions.  </p>
  11.689 +     *
  11.690 +     * @return  This decoder
  11.691 +     *
  11.692 +     */
  11.693 +    public final CharsetDecoder reset() {
  11.694 +        implReset();
  11.695 +        state = ST_RESET;
  11.696 +        return this;
  11.697 +    }
  11.698 +
  11.699 +    /**
  11.700 +     * Resets this decoder, clearing any charset-specific internal state.
  11.701 +     *
  11.702 +     * <p> The default implementation of this method does nothing.  This method
  11.703 +     * should be overridden by decoders that maintain internal state.  </p>
  11.704 +     */
  11.705 +    protected void implReset() { }
  11.706 +
  11.707 +    /**
  11.708 +     * Decodes one or more bytes into one or more characters.
  11.709 +     *
  11.710 +     * <p> This method encapsulates the basic decoding loop, decoding as many
  11.711 +     * bytes as possible until it either runs out of input, runs out of room
  11.712 +     * in the output buffer, or encounters a decoding error.  This method is
  11.713 +     * invoked by the {@link #decode decode} method, which handles result
  11.714 +     * interpretation and error recovery.
  11.715 +     *
  11.716 +     * <p> The buffers are read from, and written to, starting at their current
  11.717 +     * positions.  At most {@link Buffer#remaining in.remaining()} bytes
  11.718 +     * will be read, and at most {@link Buffer#remaining out.remaining()}
  11.719 +     * characters will be written.  The buffers' positions will be advanced to
  11.720 +     * reflect the bytes read and the characters written, but their marks and
  11.721 +     * limits will not be modified.
  11.722 +     *
  11.723 +     * <p> This method returns a {@link CoderResult} object to describe its
  11.724 +     * reason for termination, in the same manner as the {@link #decode decode}
  11.725 +     * method.  Most implementations of this method will handle decoding errors
  11.726 +     * by returning an appropriate result object for interpretation by the
  11.727 +     * {@link #decode decode} method.  An optimized implementation may instead
  11.728 +     * examine the relevant error action and implement that action itself.
  11.729 +     *
  11.730 +     * <p> An implementation of this method may perform arbitrary lookahead by
  11.731 +     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
  11.732 +     * input.  </p>
  11.733 +     *
  11.734 +     * @param  in
  11.735 +     *         The input byte buffer
  11.736 +     *
  11.737 +     * @param  out
  11.738 +     *         The output character buffer
  11.739 +     *
  11.740 +     * @return  A coder-result object describing the reason for termination
  11.741 +     */
  11.742 +    protected abstract CoderResult decodeLoop(ByteBuffer in,
  11.743 +                                              CharBuffer out);
  11.744 +
  11.745 +    /**
  11.746 +     * Convenience method that decodes the remaining content of a single input
  11.747 +     * byte buffer into a newly-allocated character buffer.
  11.748 +     *
  11.749 +     * <p> This method implements an entire <a href="#steps">decoding
  11.750 +     * operation</a>; that is, it resets this decoder, then it decodes the
  11.751 +     * bytes in the given byte buffer, and finally it flushes this
  11.752 +     * decoder.  This method should therefore not be invoked if a decoding
  11.753 +     * operation is already in progress.  </p>
  11.754 +     *
  11.755 +     * @param  in
  11.756 +     *         The input byte buffer
  11.757 +     *
  11.758 +     * @return A newly-allocated character buffer containing the result of the
  11.759 +     *         decoding operation.  The buffer's position will be zero and its
  11.760 +     *         limit will follow the last character written.
  11.761 +     *
  11.762 +     * @throws  IllegalStateException
  11.763 +     *          If a decoding operation is already in progress
  11.764 +     *
  11.765 +     * @throws  MalformedInputException
  11.766 +     *          If the byte sequence starting at the input buffer's current
  11.767 +     *          position is not legal for this charset and the current malformed-input action
  11.768 +     *          is {@link CodingErrorAction#REPORT}
  11.769 +     *
  11.770 +     * @throws  UnmappableCharacterException
  11.771 +     *          If the byte sequence starting at the input buffer's current
  11.772 +     *          position cannot be mapped to an equivalent character sequence and
  11.773 +     *          the current unmappable-character action is {@link
  11.774 +     *          CodingErrorAction#REPORT}
  11.775 +     */
  11.776 +    public final CharBuffer decode(ByteBuffer in)
  11.777 +        throws CharacterCodingException
  11.778 +    {
  11.779 +        int n = (int)(in.remaining() * averageCharsPerByte());
  11.780 +        CharBuffer out = CharBuffer.allocate(n);
  11.781 +
  11.782 +        if ((n == 0) && (in.remaining() == 0))
  11.783 +            return out;
  11.784 +        reset();
  11.785 +        for (;;) {
  11.786 +            CoderResult cr = in.hasRemaining() ?
  11.787 +                decode(in, out, true) : CoderResult.UNDERFLOW;
  11.788 +            if (cr.isUnderflow())
  11.789 +                cr = flush(out);
  11.790 +
  11.791 +            if (cr.isUnderflow())
  11.792 +                break;
  11.793 +            if (cr.isOverflow()) {
  11.794 +                n = 2*n + 1;    // Ensure progress; n might be 0!
  11.795 +                CharBuffer o = CharBuffer.allocate(n);
  11.796 +                out.flip();
  11.797 +                o.put(out);
  11.798 +                out = o;
  11.799 +                continue;
  11.800 +            }
  11.801 +            cr.throwException();
  11.802 +        }
  11.803 +        out.flip();
  11.804 +        return out;
  11.805 +    }
  11.806 +
  11.807 +
  11.808 +
  11.809 +    /**
  11.810 +     * Tells whether or not this decoder implements an auto-detecting charset.
  11.811 +     *
  11.812 +     * <p> The default implementation of this method always returns
  11.813 +     * <tt>false</tt>; it should be overridden by auto-detecting decoders to
  11.814 +     * return <tt>true</tt>.  </p>
  11.815 +     *
  11.816 +     * @return  <tt>true</tt> if, and only if, this decoder implements an
  11.817 +     *          auto-detecting charset
  11.818 +     */
  11.819 +    public boolean isAutoDetecting() {
  11.820 +        return false;
  11.821 +    }
  11.822 +
  11.823 +    /**
  11.824 +     * Tells whether or not this decoder has yet detected a
  11.825 +     * charset&nbsp;&nbsp;<i>(optional operation)</i>.
  11.826 +     *
  11.827 +     * <p> If this decoder implements an auto-detecting charset then at a
  11.828 +     * single point during a decoding operation this method may start returning
  11.829 +     * <tt>true</tt> to indicate that a specific charset has been detected in
  11.830 +     * the input byte sequence.  Once this occurs, the {@link #detectedCharset
  11.831 +     * detectedCharset} method may be invoked to retrieve the detected charset.
  11.832 +     *
  11.833 +     * <p> That this method returns <tt>false</tt> does not imply that no bytes
  11.834 +     * have yet been decoded.  Some auto-detecting decoders are capable of
  11.835 +     * decoding some, or even all, of an input byte sequence without fixing on
  11.836 +     * a particular charset.
  11.837 +     *
  11.838 +     * <p> The default implementation of this method always throws an {@link
  11.839 +     * UnsupportedOperationException}; it should be overridden by
  11.840 +     * auto-detecting decoders to return <tt>true</tt> once the input charset
  11.841 +     * has been determined.  </p>
  11.842 +     *
  11.843 +     * @return  <tt>true</tt> if, and only if, this decoder has detected a
  11.844 +     *          specific charset
  11.845 +     *
  11.846 +     * @throws  UnsupportedOperationException
  11.847 +     *          If this decoder does not implement an auto-detecting charset
  11.848 +     */
  11.849 +    public boolean isCharsetDetected() {
  11.850 +        throw new UnsupportedOperationException();
  11.851 +    }
  11.852 +
  11.853 +    /**
  11.854 +     * Retrieves the charset that was detected by this
  11.855 +     * decoder&nbsp;&nbsp;<i>(optional operation)</i>.
  11.856 +     *
  11.857 +     * <p> If this decoder implements an auto-detecting charset then this
  11.858 +     * method returns the actual charset once it has been detected.  After that
  11.859 +     * point, this method returns the same value for the duration of the
  11.860 +     * current decoding operation.  If not enough input bytes have yet been
  11.861 +     * read to determine the actual charset then this method throws an {@link
  11.862 +     * IllegalStateException}.
  11.863 +     *
  11.864 +     * <p> The default implementation of this method always throws an {@link
  11.865 +     * UnsupportedOperationException}; it should be overridden by
  11.866 +     * auto-detecting decoders to return the appropriate value.  </p>
  11.867 +     *
  11.868 +     * @return  The charset detected by this auto-detecting decoder,
  11.869 +     *          or <tt>null</tt> if the charset has not yet been determined
  11.870 +     *
  11.871 +     * @throws  IllegalStateException
  11.872 +     *          If insufficient bytes have been read to determine a charset
  11.873 +     *
  11.874 +     * @throws  UnsupportedOperationException
  11.875 +     *          If this decoder does not implement an auto-detecting charset
  11.876 +     */
  11.877 +    public Charset detectedCharset() {
  11.878 +        throw new UnsupportedOperationException();
  11.879 +    }
  11.880 +
  11.881 +
  11.882 +
  11.883 +
  11.884 +
  11.885 +
  11.886 +
  11.887 +
  11.888 +
  11.889 +
  11.890 +
  11.891 +
  11.892 +
  11.893 +
  11.894 +
  11.895 +
  11.896 +
  11.897 +
  11.898 +
  11.899 +
  11.900 +
  11.901 +
  11.902 +
  11.903 +
  11.904 +
  11.905 +
  11.906 +
  11.907 +
  11.908 +
  11.909 +
  11.910 +
  11.911 +
  11.912 +
  11.913 +
  11.914 +
  11.915 +
  11.916 +
  11.917 +
  11.918 +
  11.919 +
  11.920 +
  11.921 +
  11.922 +
  11.923 +
  11.924 +
  11.925 +
  11.926 +
  11.927 +
  11.928 +
  11.929 +
  11.930 +
  11.931 +
  11.932 +
  11.933 +
  11.934 +
  11.935 +
  11.936 +
  11.937 +
  11.938 +
  11.939 +
  11.940 +
  11.941 +
  11.942 +
  11.943 +
  11.944 +
  11.945 +
  11.946 +
  11.947 +
  11.948 +
  11.949 +
  11.950 +
  11.951 +
  11.952 +
  11.953 +
  11.954 +
  11.955 +
  11.956 +
  11.957 +
  11.958 +
  11.959 +
  11.960 +
  11.961 +
  11.962 +
  11.963 +
  11.964 +
  11.965 +
  11.966 +
  11.967 +
  11.968 +
  11.969 +
  11.970 +    private void throwIllegalStateException(int from, int to) {
  11.971 +        throw new IllegalStateException("Current state = " + stateNames[from]
  11.972 +                                        + ", new state = " + stateNames[to]);
  11.973 +    }
  11.974 +
  11.975 +}
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/CharsetEncoder.java	Thu Oct 03 15:40:35 2013 +0200
    12.3 @@ -0,0 +1,972 @@
    12.4 +/*
    12.5 + * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
    12.6 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    12.7 + *
    12.8 + *
    12.9 + *
   12.10 + *
   12.11 + *
   12.12 + *
   12.13 + *
   12.14 + *
   12.15 + *
   12.16 + *
   12.17 + *
   12.18 + *
   12.19 + *
   12.20 + *
   12.21 + *
   12.22 + *
   12.23 + *
   12.24 + *
   12.25 + *
   12.26 + *
   12.27 + */
   12.28 +
   12.29 +// -- This file was mechanically generated: Do not edit! -- //
   12.30 +
   12.31 +package java.nio.charset;
   12.32 +
   12.33 +import java.nio.Buffer;
   12.34 +import java.nio.ByteBuffer;
   12.35 +import java.nio.CharBuffer;
   12.36 +import java.nio.BufferOverflowException;
   12.37 +import java.nio.BufferUnderflowException;
   12.38 +import java.lang.ref.WeakReference;
   12.39 +import java.nio.charset.CoderMalfunctionError;                  // javadoc
   12.40 +
   12.41 +
   12.42 +/**
   12.43 + * An engine that can transform a sequence of sixteen-bit Unicode characters into a sequence of
   12.44 + * bytes in a specific charset.
   12.45 + *
   12.46 + * <a name="steps">
   12.47 + *
   12.48 + * <p> The input character sequence is provided in a character buffer or a series
   12.49 + * of such buffers.  The output byte sequence is written to a byte buffer
   12.50 + * or a series of such buffers.  An encoder should always be used by making
   12.51 + * the following sequence of method invocations, hereinafter referred to as an
   12.52 + * <i>encoding operation</i>:
   12.53 + *
   12.54 + * <ol>
   12.55 + *
   12.56 + *   <li><p> Reset the encoder via the {@link #reset reset} method, unless it
   12.57 + *   has not been used before; </p></li>
   12.58 + *
   12.59 + *   <li><p> Invoke the {@link #encode encode} method zero or more times, as
   12.60 + *   long as additional input may be available, passing <tt>false</tt> for the
   12.61 + *   <tt>endOfInput</tt> argument and filling the input buffer and flushing the
   12.62 + *   output buffer between invocations; </p></li>
   12.63 + *
   12.64 + *   <li><p> Invoke the {@link #encode encode} method one final time, passing
   12.65 + *   <tt>true</tt> for the <tt>endOfInput</tt> argument; and then </p></li>
   12.66 + *
   12.67 + *   <li><p> Invoke the {@link #flush flush} method so that the encoder can
   12.68 + *   flush any internal state to the output buffer. </p></li>
   12.69 + *
   12.70 + * </ol>
   12.71 + *
   12.72 + * Each invocation of the {@link #encode encode} method will encode as many
   12.73 + * characters as possible from the input buffer, writing the resulting bytes
   12.74 + * to the output buffer.  The {@link #encode encode} method returns when more
   12.75 + * input is required, when there is not enough room in the output buffer, or
   12.76 + * when an encoding error has occurred.  In each case a {@link CoderResult}
   12.77 + * object is returned to describe the reason for termination.  An invoker can
   12.78 + * examine this object and fill the input buffer, flush the output buffer, or
   12.79 + * attempt to recover from an encoding error, as appropriate, and try again.
   12.80 + *
   12.81 + * <a name="ce">
   12.82 + *
   12.83 + * <p> There are two general types of encoding errors.  If the input character
   12.84 + * sequence is not a legal sixteen-bit Unicode sequence then the input is considered <i>malformed</i>.  If
   12.85 + * the input character sequence is legal but cannot be mapped to a valid
   12.86 + * byte sequence in the given charset then an <i>unmappable character</i> has been encountered.
   12.87 + *
   12.88 + * <a name="cae">
   12.89 + *
   12.90 + * <p> How an encoding error is handled depends upon the action requested for
   12.91 + * that type of error, which is described by an instance of the {@link
   12.92 + * CodingErrorAction} class.  The possible error actions are to {@link
   12.93 + * CodingErrorAction#IGNORE </code>ignore<code>} the erroneous input, {@link
   12.94 + * CodingErrorAction#REPORT </code>report<code>} the error to the invoker via
   12.95 + * the returned {@link CoderResult} object, or {@link CodingErrorAction#REPLACE
   12.96 + * </code>replace<code>} the erroneous input with the current value of the
   12.97 + * replacement byte array.  The replacement
   12.98 + *
   12.99 +
  12.100 + * is initially set to the encoder's default replacement, which often
  12.101 + * (but not always) has the initial value&nbsp;<tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>;
  12.102 +
  12.103 +
  12.104 +
  12.105 +
  12.106 + *
  12.107 + * its value may be changed via the {@link #replaceWith(byte[])
  12.108 + * replaceWith} method.
  12.109 + *
  12.110 + * <p> The default action for malformed-input and unmappable-character errors
  12.111 + * is to {@link CodingErrorAction#REPORT </code>report<code>} them.  The
  12.112 + * malformed-input error action may be changed via the {@link
  12.113 + * #onMalformedInput(CodingErrorAction) onMalformedInput} method; the
  12.114 + * unmappable-character action may be changed via the {@link
  12.115 + * #onUnmappableCharacter(CodingErrorAction) onUnmappableCharacter} method.
  12.116 + *
  12.117 + * <p> This class is designed to handle many of the details of the encoding
  12.118 + * process, including the implementation of error actions.  An encoder for a
  12.119 + * specific charset, which is a concrete subclass of this class, need only
  12.120 + * implement the abstract {@link #encodeLoop encodeLoop} method, which
  12.121 + * encapsulates the basic encoding loop.  A subclass that maintains internal
  12.122 + * state should, additionally, override the {@link #implFlush implFlush} and
  12.123 + * {@link #implReset implReset} methods.
  12.124 + *
  12.125 + * <p> Instances of this class are not safe for use by multiple concurrent
  12.126 + * threads.  </p>
  12.127 + *
  12.128 + *
  12.129 + * @author Mark Reinhold
  12.130 + * @author JSR-51 Expert Group
  12.131 + * @since 1.4
  12.132 + *
  12.133 + * @see ByteBuffer
  12.134 + * @see CharBuffer
  12.135 + * @see Charset
  12.136 + * @see CharsetDecoder
  12.137 + */
  12.138 +
  12.139 +public abstract class CharsetEncoder {
  12.140 +
  12.141 +    private final Charset charset;
  12.142 +    private final float averageBytesPerChar;
  12.143 +    private final float maxBytesPerChar;
  12.144 +
  12.145 +    private byte[] replacement;
  12.146 +    private CodingErrorAction malformedInputAction
  12.147 +        = CodingErrorAction.REPORT;
  12.148 +    private CodingErrorAction unmappableCharacterAction
  12.149 +        = CodingErrorAction.REPORT;
  12.150 +
  12.151 +    // Internal states
  12.152 +    //
  12.153 +    private static final int ST_RESET   = 0;
  12.154 +    private static final int ST_CODING  = 1;
  12.155 +    private static final int ST_END     = 2;
  12.156 +    private static final int ST_FLUSHED = 3;
  12.157 +
  12.158 +    private int state = ST_RESET;
  12.159 +
  12.160 +    private static String stateNames[]
  12.161 +        = { "RESET", "CODING", "CODING_END", "FLUSHED" };
  12.162 +
  12.163 +
  12.164 +    /**
  12.165 +     * Initializes a new encoder.  The new encoder will have the given
  12.166 +     * bytes-per-char and replacement values. </p>
  12.167 +     *
  12.168 +     * @param  averageBytesPerChar
  12.169 +     *         A positive float value indicating the expected number of
  12.170 +     *         bytes that will be produced for each input character
  12.171 +     *
  12.172 +     * @param  maxBytesPerChar
  12.173 +     *         A positive float value indicating the maximum number of
  12.174 +     *         bytes that will be produced for each input character
  12.175 +     *
  12.176 +     * @param  replacement
  12.177 +     *         The initial replacement; must not be <tt>null</tt>, must have
  12.178 +     *         non-zero length, must not be longer than maxBytesPerChar,
  12.179 +     *         and must be {@link #isLegalReplacement </code>legal<code>}
  12.180 +     *
  12.181 +     * @throws  IllegalArgumentException
  12.182 +     *          If the preconditions on the parameters do not hold
  12.183 +     */
  12.184 +    protected
  12.185 +    CharsetEncoder(Charset cs,
  12.186 +                   float averageBytesPerChar,
  12.187 +                   float maxBytesPerChar,
  12.188 +                   byte[] replacement)
  12.189 +    {
  12.190 +        this.charset = cs;
  12.191 +        if (averageBytesPerChar <= 0.0f)
  12.192 +            throw new IllegalArgumentException("Non-positive "
  12.193 +                                               + "averageBytesPerChar");
  12.194 +        if (maxBytesPerChar <= 0.0f)
  12.195 +            throw new IllegalArgumentException("Non-positive "
  12.196 +                                               + "maxBytesPerChar");
  12.197 +        if (!Charset.atBugLevel("1.4")) {
  12.198 +            if (averageBytesPerChar > maxBytesPerChar)
  12.199 +                throw new IllegalArgumentException("averageBytesPerChar"
  12.200 +                                                   + " exceeds "
  12.201 +                                                   + "maxBytesPerChar");
  12.202 +        }
  12.203 +        this.replacement = replacement;
  12.204 +        this.averageBytesPerChar = averageBytesPerChar;
  12.205 +        this.maxBytesPerChar = maxBytesPerChar;
  12.206 +        replaceWith(replacement);
  12.207 +    }
  12.208 +
  12.209 +    /**
  12.210 +     * Initializes a new encoder.  The new encoder will have the given
  12.211 +     * bytes-per-char values and its replacement will be the
  12.212 +     * byte array <tt>{</tt>&nbsp;<tt>(byte)'?'</tt>&nbsp;<tt>}</tt>. </p>
  12.213 +     *
  12.214 +     * @param  averageBytesPerChar
  12.215 +     *         A positive float value indicating the expected number of
  12.216 +     *         bytes that will be produced for each input character
  12.217 +     *
  12.218 +     * @param  maxBytesPerChar
  12.219 +     *         A positive float value indicating the maximum number of
  12.220 +     *         bytes that will be produced for each input character
  12.221 +     *
  12.222 +     * @throws  IllegalArgumentException
  12.223 +     *          If the preconditions on the parameters do not hold
  12.224 +     */
  12.225 +    protected CharsetEncoder(Charset cs,
  12.226 +                             float averageBytesPerChar,
  12.227 +                             float maxBytesPerChar)
  12.228 +    {
  12.229 +        this(cs,
  12.230 +             averageBytesPerChar, maxBytesPerChar,
  12.231 +             new byte[] { (byte)'?' });
  12.232 +    }
  12.233 +
  12.234 +    /**
  12.235 +     * Returns the charset that created this encoder.  </p>
  12.236 +     *
  12.237 +     * @return  This encoder's charset
  12.238 +     */
  12.239 +    public final Charset charset() {
  12.240 +        return charset;
  12.241 +    }
  12.242 +
  12.243 +    /**
  12.244 +     * Returns this encoder's replacement value. </p>
  12.245 +     *
  12.246 +     * @return  This encoder's current replacement,
  12.247 +     *          which is never <tt>null</tt> and is never empty
  12.248 +     */
  12.249 +    public final byte[] replacement() {
  12.250 +        return replacement;
  12.251 +    }
  12.252 +
  12.253 +    /**
  12.254 +     * Changes this encoder's replacement value.
  12.255 +     *
  12.256 +     * <p> This method invokes the {@link #implReplaceWith implReplaceWith}
  12.257 +     * method, passing the new replacement, after checking that the new
  12.258 +     * replacement is acceptable.  </p>
  12.259 +     *
  12.260 +     * @param  newReplacement
  12.261 +     *
  12.262 +
  12.263 +
  12.264 +
  12.265 +
  12.266 +
  12.267 +     *         The new replacement; must not be <tt>null</tt>, must have
  12.268 +     *         non-zero length, must not be longer than the value returned by
  12.269 +     *         the {@link #maxBytesPerChar() maxBytesPerChar} method, and
  12.270 +     *         must be {@link #isLegalReplacement </code>legal<code>}
  12.271 +
  12.272 +     *
  12.273 +     * @return  This encoder
  12.274 +     *
  12.275 +     * @throws  IllegalArgumentException
  12.276 +     *          If the preconditions on the parameter do not hold
  12.277 +     */
  12.278 +    public final CharsetEncoder replaceWith(byte[] newReplacement) {
  12.279 +        if (newReplacement == null)
  12.280 +            throw new IllegalArgumentException("Null replacement");
  12.281 +        int len = newReplacement.length;
  12.282 +        if (len == 0)
  12.283 +            throw new IllegalArgumentException("Empty replacement");
  12.284 +        if (len > maxBytesPerChar)
  12.285 +            throw new IllegalArgumentException("Replacement too long");
  12.286 +
  12.287 +        if (!isLegalReplacement(newReplacement))
  12.288 +            throw new IllegalArgumentException("Illegal replacement");
  12.289 +
  12.290 +        this.replacement = newReplacement;
  12.291 +        implReplaceWith(newReplacement);
  12.292 +        return this;
  12.293 +    }
  12.294 +
  12.295 +    /**
  12.296 +     * Reports a change to this encoder's replacement value.
  12.297 +     *
  12.298 +     * <p> The default implementation of this method does nothing.  This method
  12.299 +     * should be overridden by encoders that require notification of changes to
  12.300 +     * the replacement.  </p>
  12.301 +     *
  12.302 +     * @param  newReplacement
  12.303 +     */
  12.304 +    protected void implReplaceWith(byte[] newReplacement) {
  12.305 +    }
  12.306 +
  12.307 +
  12.308 +
  12.309 +    private WeakReference<CharsetDecoder> cachedDecoder = null;
  12.310 +
  12.311 +    /**
  12.312 +     * Tells whether or not the given byte array is a legal replacement value
  12.313 +     * for this encoder.
  12.314 +     *
  12.315 +     * <p> A replacement is legal if, and only if, it is a legal sequence of
  12.316 +     * bytes in this encoder's charset; that is, it must be possible to decode
  12.317 +     * the replacement into one or more sixteen-bit Unicode characters.
  12.318 +     *
  12.319 +     * <p> The default implementation of this method is not very efficient; it
  12.320 +     * should generally be overridden to improve performance.  </p>
  12.321 +     *
  12.322 +     * @param  repl  The byte array to be tested
  12.323 +     *
  12.324 +     * @return  <tt>true</tt> if, and only if, the given byte array
  12.325 +     *          is a legal replacement value for this encoder
  12.326 +     */
  12.327 +    public boolean isLegalReplacement(byte[] repl) {
  12.328 +        WeakReference<CharsetDecoder> wr = cachedDecoder;
  12.329 +        CharsetDecoder dec = null;
  12.330 +        if ((wr == null) || ((dec = wr.get()) == null)) {
  12.331 +            dec = charset().newDecoder();
  12.332 +            dec.onMalformedInput(CodingErrorAction.REPORT);
  12.333 +            dec.onUnmappableCharacter(CodingErrorAction.REPORT);
  12.334 +            cachedDecoder = new WeakReference<CharsetDecoder>(dec);
  12.335 +        } else {
  12.336 +            dec.reset();
  12.337 +        }
  12.338 +        ByteBuffer bb = ByteBuffer.wrap(repl);
  12.339 +        CharBuffer cb = CharBuffer.allocate((int)(bb.remaining()
  12.340 +                                                  * dec.maxCharsPerByte()));
  12.341 +        CoderResult cr = dec.decode(bb, cb, true);
  12.342 +        return !cr.isError();
  12.343 +    }
  12.344 +
  12.345 +
  12.346 +
  12.347 +    /**
  12.348 +     * Returns this encoder's current action for malformed-input errors.  </p>
  12.349 +     *
  12.350 +     * @return The current malformed-input action, which is never <tt>null</tt>
  12.351 +     */
  12.352 +    public CodingErrorAction malformedInputAction() {
  12.353 +        return malformedInputAction;
  12.354 +    }
  12.355 +
  12.356 +    /**
  12.357 +     * Changes this encoder's action for malformed-input errors.  </p>
  12.358 +     *
  12.359 +     * <p> This method invokes the {@link #implOnMalformedInput
  12.360 +     * implOnMalformedInput} method, passing the new action.  </p>
  12.361 +     *
  12.362 +     * @param  newAction  The new action; must not be <tt>null</tt>
  12.363 +     *
  12.364 +     * @return  This encoder
  12.365 +     *
  12.366 +     * @throws IllegalArgumentException
  12.367 +     *         If the precondition on the parameter does not hold
  12.368 +     */
  12.369 +    public final CharsetEncoder onMalformedInput(CodingErrorAction newAction) {
  12.370 +        if (newAction == null)
  12.371 +            throw new IllegalArgumentException("Null action");
  12.372 +        malformedInputAction = newAction;
  12.373 +        implOnMalformedInput(newAction);
  12.374 +        return this;
  12.375 +    }
  12.376 +
  12.377 +    /**
  12.378 +     * Reports a change to this encoder's malformed-input action.
  12.379 +     *
  12.380 +     * <p> The default implementation of this method does nothing.  This method
  12.381 +     * should be overridden by encoders that require notification of changes to
  12.382 +     * the malformed-input action.  </p>
  12.383 +     */
  12.384 +    protected void implOnMalformedInput(CodingErrorAction newAction) { }
  12.385 +
  12.386 +    /**
  12.387 +     * Returns this encoder's current action for unmappable-character errors.
  12.388 +     * </p>
  12.389 +     *
  12.390 +     * @return The current unmappable-character action, which is never
  12.391 +     *         <tt>null</tt>
  12.392 +     */
  12.393 +    public CodingErrorAction unmappableCharacterAction() {
  12.394 +        return unmappableCharacterAction;
  12.395 +    }
  12.396 +
  12.397 +    /**
  12.398 +     * Changes this encoder's action for unmappable-character errors.
  12.399 +     *
  12.400 +     * <p> This method invokes the {@link #implOnUnmappableCharacter
  12.401 +     * implOnUnmappableCharacter} method, passing the new action.  </p>
  12.402 +     *
  12.403 +     * @param  newAction  The new action; must not be <tt>null</tt>
  12.404 +     *
  12.405 +     * @return  This encoder
  12.406 +     *
  12.407 +     * @throws IllegalArgumentException
  12.408 +     *         If the precondition on the parameter does not hold
  12.409 +     */
  12.410 +    public final CharsetEncoder onUnmappableCharacter(CodingErrorAction
  12.411 +                                                      newAction)
  12.412 +    {
  12.413 +        if (newAction == null)
  12.414 +            throw new IllegalArgumentException("Null action");
  12.415 +        unmappableCharacterAction = newAction;
  12.416 +        implOnUnmappableCharacter(newAction);
  12.417 +        return this;
  12.418 +    }
  12.419 +
  12.420 +    /**
  12.421 +     * Reports a change to this encoder's unmappable-character action.
  12.422 +     *
  12.423 +     * <p> The default implementation of this method does nothing.  This method
  12.424 +     * should be overridden by encoders that require notification of changes to
  12.425 +     * the unmappable-character action.  </p>
  12.426 +     */
  12.427 +    protected void implOnUnmappableCharacter(CodingErrorAction newAction) { }
  12.428 +
  12.429 +    /**
  12.430 +     * Returns the average number of bytes that will be produced for each
  12.431 +     * character of input.  This heuristic value may be used to estimate the size
  12.432 +     * of the output buffer required for a given input sequence. </p>
  12.433 +     *
  12.434 +     * @return  The average number of bytes produced
  12.435 +     *          per character of input
  12.436 +     */
  12.437 +    public final float averageBytesPerChar() {
  12.438 +        return averageBytesPerChar;
  12.439 +    }
  12.440 +
  12.441 +    /**
  12.442 +     * Returns the maximum number of bytes that will be produced for each
  12.443 +     * character of input.  This value may be used to compute the worst-case size
  12.444 +     * of the output buffer required for a given input sequence. </p>
  12.445 +     *
  12.446 +     * @return  The maximum number of bytes that will be produced per
  12.447 +     *          character of input
  12.448 +     */
  12.449 +    public final float maxBytesPerChar() {
  12.450 +        return maxBytesPerChar;
  12.451 +    }
  12.452 +
  12.453 +    /**
  12.454 +     * Encodes as many characters as possible from the given input buffer,
  12.455 +     * writing the results to the given output buffer.
  12.456 +     *
  12.457 +     * <p> The buffers are read from, and written to, starting at their current
  12.458 +     * positions.  At most {@link Buffer#remaining in.remaining()} characters
  12.459 +     * will be read and at most {@link Buffer#remaining out.remaining()}
  12.460 +     * bytes will be written.  The buffers' positions will be advanced to
  12.461 +     * reflect the characters read and the bytes written, but their marks and
  12.462 +     * limits will not be modified.
  12.463 +     *
  12.464 +     * <p> In addition to reading characters from the input buffer and writing
  12.465 +     * bytes to the output buffer, this method returns a {@link CoderResult}
  12.466 +     * object to describe its reason for termination:
  12.467 +     *
  12.468 +     * <ul>
  12.469 +     *
  12.470 +     *   <li><p> {@link CoderResult#UNDERFLOW} indicates that as much of the
  12.471 +     *   input buffer as possible has been encoded.  If there is no further
  12.472 +     *   input then the invoker can proceed to the next step of the
  12.473 +     *   <a href="#steps">encoding operation</a>.  Otherwise this method
  12.474 +     *   should be invoked again with further input.  </p></li>
  12.475 +     *
  12.476 +     *   <li><p> {@link CoderResult#OVERFLOW} indicates that there is
  12.477 +     *   insufficient space in the output buffer to encode any more characters.
  12.478 +     *   This method should be invoked again with an output buffer that has
  12.479 +     *   more {@linkplain Buffer#remaining remaining} bytes. This is
  12.480 +     *   typically done by draining any encoded bytes from the output
  12.481 +     *   buffer.  </p></li>
  12.482 +     *
  12.483 +     *   <li><p> A {@link CoderResult#malformedForLength
  12.484 +     *   </code>malformed-input<code>} result indicates that a malformed-input
  12.485 +     *   error has been detected.  The malformed characters begin at the input
  12.486 +     *   buffer's (possibly incremented) position; the number of malformed
  12.487 +     *   characters may be determined by invoking the result object's {@link
  12.488 +     *   CoderResult#length() length} method.  This case applies only if the
  12.489 +     *   {@link #onMalformedInput </code>malformed action<code>} of this encoder
  12.490 +     *   is {@link CodingErrorAction#REPORT}; otherwise the malformed input
  12.491 +     *   will be ignored or replaced, as requested.  </p></li>
  12.492 +     *
  12.493 +     *   <li><p> An {@link CoderResult#unmappableForLength
  12.494 +     *   </code>unmappable-character<code>} result indicates that an
  12.495 +     *   unmappable-character error has been detected.  The characters that
  12.496 +     *   encode the unmappable character begin at the input buffer's (possibly
  12.497 +     *   incremented) position; the number of such characters may be determined
  12.498 +     *   by invoking the result object's {@link CoderResult#length() length}
  12.499 +     *   method.  This case applies only if the {@link #onUnmappableCharacter
  12.500 +     *   </code>unmappable action<code>} of this encoder is {@link
  12.501 +     *   CodingErrorAction#REPORT}; otherwise the unmappable character will be
  12.502 +     *   ignored or replaced, as requested.  </p></li>
  12.503 +     *
  12.504 +     * </ul>
  12.505 +     *
  12.506 +     * In any case, if this method is to be reinvoked in the same encoding
  12.507 +     * operation then care should be taken to preserve any characters remaining
  12.508 +     * in the input buffer so that they are available to the next invocation.
  12.509 +     *
  12.510 +     * <p> The <tt>endOfInput</tt> parameter advises this method as to whether
  12.511 +     * the invoker can provide further input beyond that contained in the given
  12.512 +     * input buffer.  If there is a possibility of providing additional input
  12.513 +     * then the invoker should pass <tt>false</tt> for this parameter; if there
  12.514 +     * is no possibility of providing further input then the invoker should
  12.515 +     * pass <tt>true</tt>.  It is not erroneous, and in fact it is quite
  12.516 +     * common, to pass <tt>false</tt> in one invocation and later discover that
  12.517 +     * no further input was actually available.  It is critical, however, that
  12.518 +     * the final invocation of this method in a sequence of invocations always
  12.519 +     * pass <tt>true</tt> so that any remaining unencoded input will be treated
  12.520 +     * as being malformed.
  12.521 +     *
  12.522 +     * <p> This method works by invoking the {@link #encodeLoop encodeLoop}
  12.523 +     * method, interpreting its results, handling error conditions, and
  12.524 +     * reinvoking it as necessary.  </p>
  12.525 +     *
  12.526 +     *
  12.527 +     * @param  in
  12.528 +     *         The input character buffer
  12.529 +     *
  12.530 +     * @param  out
  12.531 +     *         The output byte buffer
  12.532 +     *
  12.533 +     * @param  endOfInput
  12.534 +     *         <tt>true</tt> if, and only if, the invoker can provide no
  12.535 +     *         additional input characters beyond those in the given buffer
  12.536 +     *
  12.537 +     * @return  A coder-result object describing the reason for termination
  12.538 +     *
  12.539 +     * @throws  IllegalStateException
  12.540 +     *          If an encoding operation is already in progress and the previous
  12.541 +     *          step was an invocation neither of the {@link #reset reset}
  12.542 +     *          method, nor of this method with a value of <tt>false</tt> for
  12.543 +     *          the <tt>endOfInput</tt> parameter, nor of this method with a
  12.544 +     *          value of <tt>true</tt> for the <tt>endOfInput</tt> parameter
  12.545 +     *          but a return value indicating an incomplete encoding operation
  12.546 +     *
  12.547 +     * @throws  CoderMalfunctionError
  12.548 +     *          If an invocation of the encodeLoop method threw
  12.549 +     *          an unexpected exception
  12.550 +     */
  12.551 +    public final CoderResult encode(CharBuffer in, ByteBuffer out,
  12.552 +                                    boolean endOfInput)
  12.553 +    {
  12.554 +        int newState = endOfInput ? ST_END : ST_CODING;
  12.555 +        if ((state != ST_RESET) && (state != ST_CODING)
  12.556 +            && !(endOfInput && (state == ST_END)))
  12.557 +            throwIllegalStateException(state, newState);
  12.558 +        state = newState;
  12.559 +
  12.560 +        for (;;) {
  12.561 +
  12.562 +            CoderResult cr;
  12.563 +            try {
  12.564 +                cr = encodeLoop(in, out);
  12.565 +            } catch (BufferUnderflowException x) {
  12.566 +                throw new CoderMalfunctionError(x);
  12.567 +            } catch (BufferOverflowException x) {
  12.568 +                throw new CoderMalfunctionError(x);
  12.569 +            }
  12.570 +
  12.571 +            if (cr.isOverflow())
  12.572 +                return cr;
  12.573 +
  12.574 +            if (cr.isUnderflow()) {
  12.575 +                if (endOfInput && in.hasRemaining()) {
  12.576 +                    cr = CoderResult.malformedForLength(in.remaining());
  12.577 +                    // Fall through to malformed-input case
  12.578 +                } else {
  12.579 +                    return cr;
  12.580 +                }
  12.581 +            }
  12.582 +
  12.583 +            CodingErrorAction action = null;
  12.584 +            if (cr.isMalformed())
  12.585 +                action = malformedInputAction;
  12.586 +            else if (cr.isUnmappable())
  12.587 +                action = unmappableCharacterAction;
  12.588 +            else
  12.589 +                assert false : cr.toString();
  12.590 +
  12.591 +            if (action == CodingErrorAction.REPORT)
  12.592 +                return cr;
  12.593 +
  12.594 +            if (action == CodingErrorAction.REPLACE) {
  12.595 +                if (out.remaining() < replacement.length)
  12.596 +                    return CoderResult.OVERFLOW;
  12.597 +                out.put(replacement);
  12.598 +            }
  12.599 +
  12.600 +            if ((action == CodingErrorAction.IGNORE)
  12.601 +                || (action == CodingErrorAction.REPLACE)) {
  12.602 +                // Skip erroneous input either way
  12.603 +                in.position(in.position() + cr.length());
  12.604 +                continue;
  12.605 +            }
  12.606 +
  12.607 +            assert false;
  12.608 +        }
  12.609 +
  12.610 +    }
  12.611 +
  12.612 +    /**
  12.613 +     * Flushes this encoder.
  12.614 +     *
  12.615 +     * <p> Some encoders maintain internal state and may need to write some
  12.616 +     * final bytes to the output buffer once the overall input sequence has
  12.617 +     * been read.
  12.618 +     *
  12.619 +     * <p> Any additional output is written to the output buffer beginning at
  12.620 +     * its current position.  At most {@link Buffer#remaining out.remaining()}
  12.621 +     * bytes will be written.  The buffer's position will be advanced
  12.622 +     * appropriately, but its mark and limit will not be modified.
  12.623 +     *
  12.624 +     * <p> If this method completes successfully then it returns {@link
  12.625 +     * CoderResult#UNDERFLOW}.  If there is insufficient room in the output
  12.626 +     * buffer then it returns {@link CoderResult#OVERFLOW}.  If this happens
  12.627 +     * then this method must be invoked again, with an output buffer that has
  12.628 +     * more room, in order to complete the current <a href="#steps">encoding
  12.629 +     * operation</a>.
  12.630 +     *
  12.631 +     * <p> If this encoder has already been flushed then invoking this method
  12.632 +     * has no effect.
  12.633 +     *
  12.634 +     * <p> This method invokes the {@link #implFlush implFlush} method to
  12.635 +     * perform the actual flushing operation.  </p>
  12.636 +     *
  12.637 +     * @param  out
  12.638 +     *         The output byte buffer
  12.639 +     *
  12.640 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
  12.641 +     *          {@link CoderResult#OVERFLOW}
  12.642 +     *
  12.643 +     * @throws  IllegalStateException
  12.644 +     *          If the previous step of the current encoding operation was an
  12.645 +     *          invocation neither of the {@link #flush flush} method nor of
  12.646 +     *          the three-argument {@link
  12.647 +     *          #encode(CharBuffer,ByteBuffer,boolean) encode} method
  12.648 +     *          with a value of <tt>true</tt> for the <tt>endOfInput</tt>
  12.649 +     *          parameter
  12.650 +     */
  12.651 +    public final CoderResult flush(ByteBuffer out) {
  12.652 +        if (state == ST_END) {
  12.653 +            CoderResult cr = implFlush(out);
  12.654 +            if (cr.isUnderflow())
  12.655 +                state = ST_FLUSHED;
  12.656 +            return cr;
  12.657 +        }
  12.658 +
  12.659 +        if (state != ST_FLUSHED)
  12.660 +            throwIllegalStateException(state, ST_FLUSHED);
  12.661 +
  12.662 +        return CoderResult.UNDERFLOW; // Already flushed
  12.663 +    }
  12.664 +
  12.665 +    /**
  12.666 +     * Flushes this encoder.
  12.667 +     *
  12.668 +     * <p> The default implementation of this method does nothing, and always
  12.669 +     * returns {@link CoderResult#UNDERFLOW}.  This method should be overridden
  12.670 +     * by encoders that may need to write final bytes to the output buffer
  12.671 +     * once the entire input sequence has been read. </p>
  12.672 +     *
  12.673 +     * @param  out
  12.674 +     *         The output byte buffer
  12.675 +     *
  12.676 +     * @return  A coder-result object, either {@link CoderResult#UNDERFLOW} or
  12.677 +     *          {@link CoderResult#OVERFLOW}
  12.678 +     */
  12.679 +    protected CoderResult implFlush(ByteBuffer out) {
  12.680 +        return CoderResult.UNDERFLOW;
  12.681 +    }
  12.682 +
  12.683 +    /**
  12.684 +     * Resets this encoder, clearing any internal state.
  12.685 +     *
  12.686 +     * <p> This method resets charset-independent state and also invokes the
  12.687 +     * {@link #implReset() implReset} method in order to perform any
  12.688 +     * charset-specific reset actions.  </p>
  12.689 +     *
  12.690 +     * @return  This encoder
  12.691 +     *
  12.692 +     */
  12.693 +    public final CharsetEncoder reset() {
  12.694 +        implReset();
  12.695 +        state = ST_RESET;
  12.696 +        return this;
  12.697 +    }
  12.698 +
  12.699 +    /**
  12.700 +     * Resets this encoder, clearing any charset-specific internal state.
  12.701 +     *
  12.702 +     * <p> The default implementation of this method does nothing.  This method
  12.703 +     * should be overridden by encoders that maintain internal state.  </p>
  12.704 +     */
  12.705 +    protected void implReset() { }
  12.706 +
  12.707 +    /**
  12.708 +     * Encodes one or more characters into one or more bytes.
  12.709 +     *
  12.710 +     * <p> This method encapsulates the basic encoding loop, encoding as many
  12.711 +     * characters as possible until it either runs out of input, runs out of room
  12.712 +     * in the output buffer, or encounters an encoding error.  This method is
  12.713 +     * invoked by the {@link #encode encode} method, which handles result
  12.714 +     * interpretation and error recovery.
  12.715 +     *
  12.716 +     * <p> The buffers are read from, and written to, starting at their current
  12.717 +     * positions.  At most {@link Buffer#remaining in.remaining()} characters
  12.718 +     * will be read, and at most {@link Buffer#remaining out.remaining()}
  12.719 +     * bytes will be written.  The buffers' positions will be advanced to
  12.720 +     * reflect the characters read and the bytes written, but their marks and
  12.721 +     * limits will not be modified.
  12.722 +     *
  12.723 +     * <p> This method returns a {@link CoderResult} object to describe its
  12.724 +     * reason for termination, in the same manner as the {@link #encode encode}
  12.725 +     * method.  Most implementations of this method will handle encoding errors
  12.726 +     * by returning an appropriate result object for interpretation by the
  12.727 +     * {@link #encode encode} method.  An optimized implementation may instead
  12.728 +     * examine the relevant error action and implement that action itself.
  12.729 +     *
  12.730 +     * <p> An implementation of this method may perform arbitrary lookahead by
  12.731 +     * returning {@link CoderResult#UNDERFLOW} until it receives sufficient
  12.732 +     * input.  </p>
  12.733 +     *
  12.734 +     * @param  in
  12.735 +     *         The input character buffer
  12.736 +     *
  12.737 +     * @param  out
  12.738 +     *         The output byte buffer
  12.739 +     *
  12.740 +     * @return  A coder-result object describing the reason for termination
  12.741 +     */
  12.742 +    protected abstract CoderResult encodeLoop(CharBuffer in,
  12.743 +                                              ByteBuffer out);
  12.744 +
  12.745 +    /**
  12.746 +     * Convenience method that encodes the remaining content of a single input
  12.747 +     * character buffer into a newly-allocated byte buffer.
  12.748 +     *
  12.749 +     * <p> This method implements an entire <a href="#steps">encoding
  12.750 +     * operation</a>; that is, it resets this encoder, then it encodes the
  12.751 +     * characters in the given character buffer, and finally it flushes this
  12.752 +     * encoder.  This method should therefore not be invoked if an encoding
  12.753 +     * operation is already in progress.  </p>
  12.754 +     *
  12.755 +     * @param  in
  12.756 +     *         The input character buffer
  12.757 +     *
  12.758 +     * @return A newly-allocated byte buffer containing the result of the
  12.759 +     *         encoding operation.  The buffer's position will be zero and its
  12.760 +     *         limit will follow the last byte written.
  12.761 +     *
  12.762 +     * @throws  IllegalStateException
  12.763 +     *          If an encoding operation is already in progress
  12.764 +     *
  12.765 +     * @throws  MalformedInputException
  12.766 +     *          If the character sequence starting at the input buffer's current
  12.767 +     *          position is not a legal sixteen-bit Unicode sequence and the current malformed-input action
  12.768 +     *          is {@link CodingErrorAction#REPORT}
  12.769 +     *
  12.770 +     * @throws  UnmappableCharacterException
  12.771 +     *          If the character sequence starting at the input buffer's current
  12.772 +     *          position cannot be mapped to an equivalent byte sequence and
  12.773 +     *          the current unmappable-character action is {@link
  12.774 +     *          CodingErrorAction#REPORT}
  12.775 +     */
  12.776 +    public final ByteBuffer encode(CharBuffer in)
  12.777 +        throws CharacterCodingException
  12.778 +    {
  12.779 +        int n = (int)(in.remaining() * averageBytesPerChar());
  12.780 +        ByteBuffer out = ByteBuffer.allocate(n);
  12.781 +
  12.782 +        if ((n == 0) && (in.remaining() == 0))
  12.783 +            return out;
  12.784 +        reset();
  12.785 +        for (;;) {
  12.786 +            CoderResult cr = in.hasRemaining() ?
  12.787 +                encode(in, out, true) : CoderResult.UNDERFLOW;
  12.788 +            if (cr.isUnderflow())
  12.789 +                cr = flush(out);
  12.790 +
  12.791 +            if (cr.isUnderflow())
  12.792 +                break;
  12.793 +            if (cr.isOverflow()) {
  12.794 +                n = 2*n + 1;    // Ensure progress; n might be 0!
  12.795 +                ByteBuffer o = ByteBuffer.allocate(n);
  12.796 +                out.flip();
  12.797 +                o.put(out);
  12.798 +                out = o;
  12.799 +                continue;
  12.800 +            }
  12.801 +            cr.throwException();
  12.802 +        }
  12.803 +        out.flip();
  12.804 +        return out;
  12.805 +    }
  12.806 +
  12.807 +
  12.808 +
  12.809 +
  12.810 +
  12.811 +
  12.812 +
  12.813 +
  12.814 +
  12.815 +
  12.816 +
  12.817 +
  12.818 +
  12.819 +
  12.820 +
  12.821 +
  12.822 +
  12.823 +
  12.824 +
  12.825 +
  12.826 +
  12.827 +
  12.828 +
  12.829 +
  12.830 +
  12.831 +
  12.832 +
  12.833 +
  12.834 +
  12.835 +
  12.836 +
  12.837 +
  12.838 +
  12.839 +
  12.840 +
  12.841 +
  12.842 +
  12.843 +
  12.844 +
  12.845 +
  12.846 +
  12.847 +
  12.848 +
  12.849 +
  12.850 +
  12.851 +
  12.852 +
  12.853 +
  12.854 +
  12.855 +
  12.856 +
  12.857 +
  12.858 +
  12.859 +
  12.860 +
  12.861 +
  12.862 +
  12.863 +
  12.864 +
  12.865 +
  12.866 +
  12.867 +
  12.868 +
  12.869 +
  12.870 +
  12.871 +
  12.872 +
  12.873 +
  12.874 +
  12.875 +
  12.876 +
  12.877 +
  12.878 +
  12.879 +
  12.880 +
  12.881 +
  12.882 +
  12.883 +
  12.884 +
  12.885 +    private boolean canEncode(CharBuffer cb) {
  12.886 +        if (state == ST_FLUSHED)
  12.887 +            reset();
  12.888 +        else if (state != ST_RESET)
  12.889 +            throwIllegalStateException(state, ST_CODING);
  12.890 +        CodingErrorAction ma = malformedInputAction();
  12.891 +        CodingErrorAction ua = unmappableCharacterAction();
  12.892 +        try {
  12.893 +            onMalformedInput(CodingErrorAction.REPORT);
  12.894 +            onUnmappableCharacter(CodingErrorAction.REPORT);
  12.895 +            encode(cb);
  12.896 +        } catch (CharacterCodingException x) {
  12.897 +            return false;
  12.898 +        } finally {
  12.899 +            onMalformedInput(ma);
  12.900 +            onUnmappableCharacter(ua);
  12.901 +            reset();
  12.902 +        }
  12.903 +        return true;
  12.904 +    }
  12.905 +
  12.906 +    /**
  12.907 +     * Tells whether or not this encoder can encode the given character.
  12.908 +     *
  12.909 +     * <p> This method returns <tt>false</tt> if the given character is a
  12.910 +     * surrogate character; such characters can be interpreted only when they
  12.911 +     * are members of a pair consisting of a high surrogate followed by a low
  12.912 +     * surrogate.  The {@link #canEncode(java.lang.CharSequence)
  12.913 +     * canEncode(CharSequence)} method may be used to test whether or not a
  12.914 +     * character sequence can be encoded.
  12.915 +     *
  12.916 +     * <p> This method may modify this encoder's state; it should therefore not
  12.917 +     * be invoked if an <a href="#steps">encoding operation</a> is already in
  12.918 +     * progress.
  12.919 +     *
  12.920 +     * <p> The default implementation of this method is not very efficient; it
  12.921 +     * should generally be overridden to improve performance.  </p>
  12.922 +     *
  12.923 +     * @return  <tt>true</tt> if, and only if, this encoder can encode
  12.924 +     *          the given character
  12.925 +     *
  12.926 +     * @throws  IllegalStateException
  12.927 +     *          If an encoding operation is already in progress
  12.928 +     */
  12.929 +    public boolean canEncode(char c) {
  12.930 +        CharBuffer cb = CharBuffer.allocate(1);
  12.931 +        cb.put(c);
  12.932 +        cb.flip();
  12.933 +        return canEncode(cb);
  12.934 +    }
  12.935 +
  12.936 +    /**
  12.937 +     * Tells whether or not this encoder can encode the given character
  12.938 +     * sequence.
  12.939 +     *
  12.940 +     * <p> If this method returns <tt>false</tt> for a particular character
  12.941 +     * sequence then more information about why the sequence cannot be encoded
  12.942 +     * may be obtained by performing a full <a href="#steps">encoding
  12.943 +     * operation</a>.
  12.944 +     *
  12.945 +     * <p> This method may modify this encoder's state; it should therefore not
  12.946 +     * be invoked if an encoding operation is already in progress.
  12.947 +     *
  12.948 +     * <p> The default implementation of this method is not very efficient; it
  12.949 +     * should generally be overridden to improve performance.  </p>
  12.950 +     *
  12.951 +     * @return  <tt>true</tt> if, and only if, this encoder can encode
  12.952 +     *          the given character without throwing any exceptions and without
  12.953 +     *          performing any replacements
  12.954 +     *
  12.955 +     * @throws  IllegalStateException
  12.956 +     *          If an encoding operation is already in progress
  12.957 +     */
  12.958 +    public boolean canEncode(CharSequence cs) {
  12.959 +        CharBuffer cb;
  12.960 +        if (cs instanceof CharBuffer)
  12.961 +            cb = ((CharBuffer)cs).duplicate();
  12.962 +        else
  12.963 +            cb = CharBuffer.wrap(cs.toString());
  12.964 +        return canEncode(cb);
  12.965 +    }
  12.966 +
  12.967 +
  12.968 +
  12.969 +
  12.970 +    private void throwIllegalStateException(int from, int to) {
  12.971 +        throw new IllegalStateException("Current state = " + stateNames[from]
  12.972 +                                        + ", new state = " + stateNames[to]);
  12.973 +    }
  12.974 +
  12.975 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/IllegalCharsetNameException.java	Thu Oct 03 15:40:35 2013 +0200
    13.3 @@ -0,0 +1,68 @@
    13.4 +/*
    13.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
    13.6 + *
    13.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    13.8 + *
    13.9 + *
   13.10 + *
   13.11 + *
   13.12 + *
   13.13 + *
   13.14 + *
   13.15 + *
   13.16 + *
   13.17 + *
   13.18 + *
   13.19 + *
   13.20 + *
   13.21 + *
   13.22 + *
   13.23 + *
   13.24 + *
   13.25 + *
   13.26 + *
   13.27 + *
   13.28 + *
   13.29 + */
   13.30 +
   13.31 +// -- This file was mechanically generated: Do not edit! -- //
   13.32 +
   13.33 +package java.nio.charset;
   13.34 +
   13.35 +
   13.36 +/**
   13.37 + * Unchecked exception thrown when a string that is not a
   13.38 + * <a href=Charset.html#names>legal charset name</a> is used as such.
   13.39 + *
   13.40 + * @since 1.4
   13.41 + */
   13.42 +
   13.43 +public class IllegalCharsetNameException
   13.44 +    extends IllegalArgumentException
   13.45 +{
   13.46 +
   13.47 +    private static final long serialVersionUID = 1457525358470002989L;
   13.48 +
   13.49 +    private String charsetName;
   13.50 +
   13.51 +    /**
   13.52 +     * Constructs an instance of this class. </p>
   13.53 +     *
   13.54 +     * @param  charsetName
   13.55 +     *         The illegal charset name
   13.56 +     */
   13.57 +    public IllegalCharsetNameException(String charsetName) {
   13.58 +        super(String.valueOf(charsetName));
   13.59 +	this.charsetName = charsetName;
   13.60 +    }
   13.61 +
   13.62 +    /**
   13.63 +     * Retrieves the illegal charset name. </p>
   13.64 +     *
   13.65 +     * @return  The illegal charset name
   13.66 +     */
   13.67 +    public String getCharsetName() {
   13.68 +        return charsetName;
   13.69 +    }
   13.70 +
   13.71 +}
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/rt/emul/compact/src/main/java/java/nio/charset/UnsupportedCharsetException.java	Thu Oct 03 15:40:35 2013 +0200
    14.3 @@ -0,0 +1,68 @@
    14.4 +/*
    14.5 + * Copyright (c) 2000, 2007, Oracle and/or its affiliates. All rights reserved.
    14.6 + *
    14.7 + * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
    14.8 + *
    14.9 + *
   14.10 + *
   14.11 + *
   14.12 + *
   14.13 + *
   14.14 + *
   14.15 + *
   14.16 + *
   14.17 + *
   14.18 + *
   14.19 + *
   14.20 + *
   14.21 + *
   14.22 + *
   14.23 + *
   14.24 + *
   14.25 + *
   14.26 + *
   14.27 + *
   14.28 + *
   14.29 + */
   14.30 +
   14.31 +// -- This file was mechanically generated: Do not edit! -- //
   14.32 +
   14.33 +package java.nio.charset;
   14.34 +
   14.35 +
   14.36 +/**
   14.37 + * Unchecked exception thrown when no support is available
   14.38 + * for a requested charset.
   14.39 + *
   14.40 + * @since 1.4
   14.41 + */
   14.42 +
   14.43 +public class UnsupportedCharsetException
   14.44 +    extends IllegalArgumentException
   14.45 +{
   14.46 +
   14.47 +    private static final long serialVersionUID = 1490765524727386367L;
   14.48 +
   14.49 +    private String charsetName;
   14.50 +
   14.51 +    /**
   14.52 +     * Constructs an instance of this class. </p>
   14.53 +     *
   14.54 +     * @param  charsetName
   14.55 +     *         The name of the unsupported charset
   14.56 +     */
   14.57 +    public UnsupportedCharsetException(String charsetName) {
   14.58 +        super(String.valueOf(charsetName));
   14.59 +	this.charsetName = charsetName;
   14.60 +    }
   14.61 +
   14.62 +    /**
   14.63 +     * Retrieves the name of the unsupported charset. </p>
   14.64 +     *
   14.65 +     * @return  The name of the unsupported charset
   14.66 +     */
   14.67 +    public String getCharsetName() {
   14.68 +        return charsetName;
   14.69 +    }
   14.70 +
   14.71 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/rt/emul/compact/src/main/java/java/security/AccessController.java	Thu Oct 03 15:40:35 2013 +0200
    15.3 @@ -0,0 +1,557 @@
    15.4 +/*
    15.5 + * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
    15.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    15.7 + *
    15.8 + * This code is free software; you can redistribute it and/or modify it
    15.9 + * under the terms of the GNU General Public License version 2 only, as
   15.10 + * published by the Free Software Foundation.  Oracle designates this
   15.11 + * particular file as subject to the "Classpath" exception as provided
   15.12 + * by Oracle in the LICENSE file that accompanied this code.
   15.13 + *
   15.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   15.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   15.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   15.17 + * version 2 for more details (a copy is included in the LICENSE file that
   15.18 + * accompanied this code).
   15.19 + *
   15.20 + * You should have received a copy of the GNU General Public License version
   15.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   15.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   15.23 + *
   15.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   15.25 + * or visit www.oracle.com if you need additional information or have any
   15.26 + * questions.
   15.27 + */
   15.28 +
   15.29 +package java.security;
   15.30 +
   15.31 +import sun.security.util.Debug;
   15.32 +
   15.33 +/**
   15.34 + * <p> The AccessController class is used for access control operations
   15.35 + * and decisions.
   15.36 + *
   15.37 + * <p> More specifically, the AccessController class is used for
   15.38 + * three purposes:
   15.39 + *
   15.40 + * <ul>
   15.41 + * <li> to decide whether an access to a critical system
   15.42 + * resource is to be allowed or denied, based on the security policy
   15.43 + * currently in effect,<p>
   15.44 + * <li>to mark code as being "privileged", thus affecting subsequent
   15.45 + * access determinations, and<p>
   15.46 + * <li>to obtain a "snapshot" of the current calling context so
   15.47 + * access-control decisions from a different context can be made with
   15.48 + * respect to the saved context. </ul>
   15.49 + *
   15.50 + * <p> The {@link #checkPermission(Permission) checkPermission} method
   15.51 + * determines whether the access request indicated by a specified
   15.52 + * permission should be granted or denied. A sample call appears
   15.53 + * below. In this example, <code>checkPermission</code> will determine
   15.54 + * whether or not to grant "read" access to the file named "testFile" in
   15.55 + * the "/temp" directory.
   15.56 + *
   15.57 + * <pre>
   15.58 + *
   15.59 + * FilePermission perm = new FilePermission("/temp/testFile", "read");
   15.60 + * AccessController.checkPermission(perm);
   15.61 + *
   15.62 + * </pre>
   15.63 + *
   15.64 + * <p> If a requested access is allowed,
   15.65 + * <code>checkPermission</code> returns quietly. If denied, an
   15.66 + * AccessControlException is
   15.67 + * thrown. AccessControlException can also be thrown if the requested
   15.68 + * permission is of an incorrect type or contains an invalid value.
   15.69 + * Such information is given whenever possible.
   15.70 + *
   15.71 + * Suppose the current thread traversed m callers, in the order of caller 1
   15.72 + * to caller 2 to caller m. Then caller m invoked the
   15.73 + * <code>checkPermission</code> method.
   15.74 + * The <code>checkPermission </code>method determines whether access
   15.75 + * is granted or denied based on the following algorithm:
   15.76 + *
   15.77 + *  <pre> {@code
   15.78 + * for (int i = m; i > 0; i--) {
   15.79 + *
   15.80 + *     if (caller i's domain does not have the permission)
   15.81 + *         throw AccessControlException
   15.82 + *
   15.83 + *     else if (caller i is marked as privileged) {
   15.84 + *         if (a context was specified in the call to doPrivileged)
   15.85 + *             context.checkPermission(permission)
   15.86 + *         return;
   15.87 + *     }
   15.88 + * };
   15.89 + *
   15.90 + * // Next, check the context inherited when the thread was created.
   15.91 + * // Whenever a new thread is created, the AccessControlContext at
   15.92 + * // that time is stored and associated with the new thread, as the
   15.93 + * // "inherited" context.
   15.94 + *
   15.95 + * inheritedContext.checkPermission(permission);
   15.96 + * }</pre>
   15.97 + *
   15.98 + * <p> A caller can be marked as being "privileged"
   15.99 + * (see {@link #doPrivileged(PrivilegedAction) doPrivileged} and below).
  15.100 + * When making access control decisions, the <code>checkPermission</code>
  15.101 + * method stops checking if it reaches a caller that
  15.102 + * was marked as "privileged" via a <code>doPrivileged</code>
  15.103 + * call without a context argument (see below for information about a
  15.104 + * context argument). If that caller's domain has the
  15.105 + * specified permission, no further checking is done and
  15.106 + * <code>checkPermission</code>
  15.107 + * returns quietly, indicating that the requested access is allowed.
  15.108 + * If that domain does not have the specified permission, an exception
  15.109 + * is thrown, as usual.
  15.110 + *
  15.111 + * <p> The normal use of the "privileged" feature is as follows. If you
  15.112 + * don't need to return a value from within the "privileged" block, do
  15.113 + * the following:
  15.114 + *
  15.115 + *  <pre> {@code
  15.116 + * somemethod() {
  15.117 + *     ...normal code here...
  15.118 + *     AccessController.doPrivileged(new PrivilegedAction<Void>() {
  15.119 + *         public Void run() {
  15.120 + *             // privileged code goes here, for example:
  15.121 + *             System.loadLibrary("awt");
  15.122 + *             return null; // nothing to return
  15.123 + *         }
  15.124 + *     });
  15.125 + *     ...normal code here...
  15.126 + * }}</pre>
  15.127 + *
  15.128 + * <p>
  15.129 + * PrivilegedAction is an interface with a single method, named
  15.130 + * <code>run</code>.
  15.131 + * The above example shows creation of an implementation
  15.132 + * of that interface; a concrete implementation of the
  15.133 + * <code>run</code> method is supplied.
  15.134 + * When the call to <code>doPrivileged</code> is made, an
  15.135 + * instance of the PrivilegedAction implementation is passed
  15.136 + * to it. The <code>doPrivileged</code> method calls the
  15.137 + * <code>run</code> method from the PrivilegedAction
  15.138 + * implementation after enabling privileges, and returns the
  15.139 + * <code>run</code> method's return value as the
  15.140 + * <code>doPrivileged</code> return value (which is
  15.141 + * ignored in this example).
  15.142 + *
  15.143 + * <p> If you need to return a value, you can do something like the following:
  15.144 + *
  15.145 + *  <pre> {@code
  15.146 + * somemethod() {
  15.147 + *     ...normal code here...
  15.148 + *     String user = AccessController.doPrivileged(
  15.149 + *         new PrivilegedAction<String>() {
  15.150 + *         public String run() {
  15.151 + *             return System.getProperty("user.name");
  15.152 + *             }
  15.153 + *         });
  15.154 + *     ...normal code here...
  15.155 + * }}</pre>
  15.156 + *
  15.157 + * <p>If the action performed in your <code>run</code> method could
  15.158 + * throw a "checked" exception (those listed in the <code>throws</code> clause
  15.159 + * of a method), then you need to use the
  15.160 + * <code>PrivilegedExceptionAction</code> interface instead of the
  15.161 + * <code>PrivilegedAction</code> interface:
  15.162 + *
  15.163 + *  <pre> {@code
  15.164 + * somemethod() throws FileNotFoundException {
  15.165 + *     ...normal code here...
  15.166 + *     try {
  15.167 + *         FileInputStream fis = AccessController.doPrivileged(
  15.168 + *         new PrivilegedExceptionAction<FileInputStream>() {
  15.169 + *             public FileInputStream run() throws FileNotFoundException {
  15.170 + *                 return new FileInputStream("someFile");
  15.171 + *             }
  15.172 + *         });
  15.173 + *     } catch (PrivilegedActionException e) {
  15.174 + *         // e.getException() should be an instance of FileNotFoundException,
  15.175 + *         // as only "checked" exceptions will be "wrapped" in a
  15.176 + *         // PrivilegedActionException.
  15.177 + *         throw (FileNotFoundException) e.getException();
  15.178 + *     }
  15.179 + *     ...normal code here...
  15.180 + *  }}</pre>
  15.181 + *
  15.182 + * <p> Be *very* careful in your use of the "privileged" construct, and
  15.183 + * always remember to make the privileged code section as small as possible.
  15.184 + *
  15.185 + * <p> Note that <code>checkPermission</code> always performs security checks
  15.186 + * within the context of the currently executing thread.
  15.187 + * Sometimes a security check that should be made within a given context
  15.188 + * will actually need to be done from within a
  15.189 + * <i>different</i> context (for example, from within a worker thread).
  15.190 + * The {@link #getContext() getContext} method and
  15.191 + * AccessControlContext class are provided
  15.192 + * for this situation. The <code>getContext</code> method takes a "snapshot"
  15.193 + * of the current calling context, and places
  15.194 + * it in an AccessControlContext object, which it returns. A sample call is
  15.195 + * the following:
  15.196 + *
  15.197 + * <pre>
  15.198 + *
  15.199 + * AccessControlContext acc = AccessController.getContext()
  15.200 + *
  15.201 + * </pre>
  15.202 + *
  15.203 + * <p>
  15.204 + * AccessControlContext itself has a <code>checkPermission</code> method
  15.205 + * that makes access decisions based on the context <i>it</i> encapsulates,
  15.206 + * rather than that of the current execution thread.
  15.207 + * Code within a different context can thus call that method on the
  15.208 + * previously-saved AccessControlContext object. A sample call is the
  15.209 + * following:
  15.210 + *
  15.211 + * <pre>
  15.212 + *
  15.213 + * acc.checkPermission(permission)
  15.214 + *
  15.215 + * </pre>
  15.216 + *
  15.217 + * <p> There are also times where you don't know a priori which permissions
  15.218 + * to check the context against. In these cases you can use the
  15.219 + * doPrivileged method that takes a context:
  15.220 + *
  15.221 + *  <pre> {@code
  15.222 + * somemethod() {
  15.223 + *     AccessController.doPrivileged(new PrivilegedAction<Object>() {
  15.224 + *         public Object run() {
  15.225 + *             // Code goes here. Any permission checks within this
  15.226 + *             // run method will require that the intersection of the
  15.227 + *             // callers protection domain and the snapshot's
  15.228 + *             // context have the desired permission.
  15.229 + *         }
  15.230 + *     }, acc);
  15.231 + *     ...normal code here...
  15.232 + * }}</pre>
  15.233 + *
  15.234 + * @see AccessControlContext
  15.235 + *
  15.236 + * @author Li Gong
  15.237 + * @author Roland Schemers
  15.238 + */
  15.239 +
  15.240 +public final class AccessController {
  15.241 +
  15.242 +    /**
  15.243 +     * Don't allow anyone to instantiate an AccessController
  15.244 +     */
  15.245 +    private AccessController() { }
  15.246 +
  15.247 +    /**
  15.248 +     * Performs the specified <code>PrivilegedAction</code> with privileges
  15.249 +     * enabled. The action is performed with <i>all</i> of the permissions
  15.250 +     * possessed by the caller's protection domain.
  15.251 +     *
  15.252 +     * <p> If the action's <code>run</code> method throws an (unchecked)
  15.253 +     * exception, it will propagate through this method.
  15.254 +     *
  15.255 +     * <p> Note that any DomainCombiner associated with the current
  15.256 +     * AccessControlContext will be ignored while the action is performed.
  15.257 +     *
  15.258 +     * @param action the action to be performed.
  15.259 +     *
  15.260 +     * @return the value returned by the action's <code>run</code> method.
  15.261 +     *
  15.262 +     * @exception NullPointerException if the action is <code>null</code>
  15.263 +     *
  15.264 +     * @see #doPrivileged(PrivilegedAction,AccessControlContext)
  15.265 +     * @see #doPrivileged(PrivilegedExceptionAction)
  15.266 +     * @see #doPrivilegedWithCombiner(PrivilegedAction)
  15.267 +     * @see java.security.DomainCombiner
  15.268 +     */
  15.269 +
  15.270 +    public static native <T> T doPrivileged(PrivilegedAction<T> action);
  15.271 +
  15.272 +    /**
  15.273 +     * Performs the specified <code>PrivilegedAction</code> with privileges
  15.274 +     * enabled. The action is performed with <i>all</i> of the permissions
  15.275 +     * possessed by the caller's protection domain.
  15.276 +     *
  15.277 +     * <p> If the action's <code>run</code> method throws an (unchecked)
  15.278 +     * exception, it will propagate through this method.
  15.279 +     *
  15.280 +     * <p> This method preserves the current AccessControlContext's
  15.281 +     * DomainCombiner (which may be null) while the action is performed.
  15.282 +     *
  15.283 +     * @param action the action to be performed.
  15.284 +     *
  15.285 +     * @return the value returned by the action's <code>run</code> method.
  15.286 +     *
  15.287 +     * @exception NullPointerException if the action is <code>null</code>
  15.288 +     *
  15.289 +     * @see #doPrivileged(PrivilegedAction)
  15.290 +     * @see java.security.DomainCombiner
  15.291 +     *
  15.292 +     * @since 1.6
  15.293 +     */
  15.294 +    public static <T> T doPrivilegedWithCombiner(PrivilegedAction<T> action) {
  15.295 +
  15.296 +        DomainCombiner dc = null;
  15.297 +        AccessControlContext acc = getStackAccessControlContext();
  15.298 +        if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
  15.299 +            return AccessController.doPrivileged(action);
  15.300 +        }
  15.301 +        return AccessController.doPrivileged(action, preserveCombiner(dc));
  15.302 +    }
  15.303 +
  15.304 +
  15.305 +    /**
  15.306 +     * Performs the specified <code>PrivilegedAction</code> with privileges
  15.307 +     * enabled and restricted by the specified
  15.308 +     * <code>AccessControlContext</code>.
  15.309 +     * The action is performed with the intersection of the permissions
  15.310 +     * possessed by the caller's protection domain, and those possessed
  15.311 +     * by the domains represented by the specified
  15.312 +     * <code>AccessControlContext</code>.
  15.313 +     * <p>
  15.314 +     * If the action's <code>run</code> method throws an (unchecked) exception,
  15.315 +     * it will propagate through this method.
  15.316 +     *
  15.317 +     * @param action the action to be performed.
  15.318 +     * @param context an <i>access control context</i>
  15.319 +     *                representing the restriction to be applied to the
  15.320 +     *                caller's domain's privileges before performing
  15.321 +     *                the specified action.  If the context is
  15.322 +     *                <code>null</code>,
  15.323 +     *                then no additional restriction is applied.
  15.324 +     *
  15.325 +     * @return the value returned by the action's <code>run</code> method.
  15.326 +     *
  15.327 +     * @exception NullPointerException if the action is <code>null</code>
  15.328 +     *
  15.329 +     * @see #doPrivileged(PrivilegedAction)
  15.330 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  15.331 +     */
  15.332 +    public static native <T> T doPrivileged(PrivilegedAction<T> action,
  15.333 +                                            AccessControlContext context);
  15.334 +
  15.335 +    /**
  15.336 +     * Performs the specified <code>PrivilegedExceptionAction</code> with
  15.337 +     * privileges enabled.  The action is performed with <i>all</i> of the
  15.338 +     * permissions possessed by the caller's protection domain.
  15.339 +     *
  15.340 +     * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
  15.341 +     * exception, it will propagate through this method.
  15.342 +     *
  15.343 +     * <p> Note that any DomainCombiner associated with the current
  15.344 +     * AccessControlContext will be ignored while the action is performed.
  15.345 +     *
  15.346 +     * @param action the action to be performed
  15.347 +     *
  15.348 +     * @return the value returned by the action's <code>run</code> method
  15.349 +     *
  15.350 +     * @exception PrivilegedActionException if the specified action's
  15.351 +     *         <code>run</code> method threw a <i>checked</i> exception
  15.352 +     * @exception NullPointerException if the action is <code>null</code>
  15.353 +     *
  15.354 +     * @see #doPrivileged(PrivilegedAction)
  15.355 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  15.356 +     * @see #doPrivilegedWithCombiner(PrivilegedExceptionAction)
  15.357 +     * @see java.security.DomainCombiner
  15.358 +     */
  15.359 +    public static native <T> T
  15.360 +        doPrivileged(PrivilegedExceptionAction<T> action)
  15.361 +        throws PrivilegedActionException;
  15.362 +
  15.363 +
  15.364 +    /**
  15.365 +     * Performs the specified <code>PrivilegedExceptionAction</code> with
  15.366 +     * privileges enabled.  The action is performed with <i>all</i> of the
  15.367 +     * permissions possessed by the caller's protection domain.
  15.368 +     *
  15.369 +     * <p> If the action's <code>run</code> method throws an <i>unchecked</i>
  15.370 +     * exception, it will propagate through this method.
  15.371 +     *
  15.372 +     * <p> This method preserves the current AccessControlContext's
  15.373 +     * DomainCombiner (which may be null) while the action is performed.
  15.374 +     *
  15.375 +     * @param action the action to be performed.
  15.376 +     *
  15.377 +     * @return the value returned by the action's <code>run</code> method
  15.378 +     *
  15.379 +     * @exception PrivilegedActionException if the specified action's
  15.380 +     *         <code>run</code> method threw a <i>checked</i> exception
  15.381 +     * @exception NullPointerException if the action is <code>null</code>
  15.382 +     *
  15.383 +     * @see #doPrivileged(PrivilegedAction)
  15.384 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  15.385 +     * @see java.security.DomainCombiner
  15.386 +     *
  15.387 +     * @since 1.6
  15.388 +     */
  15.389 +    public static <T> T doPrivilegedWithCombiner
  15.390 +        (PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
  15.391 +
  15.392 +        DomainCombiner dc = null;
  15.393 +        AccessControlContext acc = getStackAccessControlContext();
  15.394 +        if (acc == null || (dc = acc.getAssignedCombiner()) == null) {
  15.395 +            return AccessController.doPrivileged(action);
  15.396 +        }
  15.397 +        return AccessController.doPrivileged(action, preserveCombiner(dc));
  15.398 +    }
  15.399 +
  15.400 +    /**
  15.401 +     * preserve the combiner across the doPrivileged call
  15.402 +     */
  15.403 +    private static AccessControlContext preserveCombiner
  15.404 +                                        (DomainCombiner combiner) {
  15.405 +
  15.406 +        /**
  15.407 +         * callerClass[0] = Reflection.getCallerClass
  15.408 +         * callerClass[1] = AccessController.preserveCombiner
  15.409 +         * callerClass[2] = AccessController.doPrivileged
  15.410 +         * callerClass[3] = caller
  15.411 +         */
  15.412 +        final Class callerClass = sun.reflect.Reflection.getCallerClass(3);
  15.413 +        ProtectionDomain callerPd = doPrivileged
  15.414 +            (new PrivilegedAction<ProtectionDomain>() {
  15.415 +            public ProtectionDomain run() {
  15.416 +                return callerClass.getProtectionDomain();
  15.417 +            }
  15.418 +        });
  15.419 +
  15.420 +        // perform 'combine' on the caller of doPrivileged,
  15.421 +        // even if the caller is from the bootclasspath
  15.422 +        ProtectionDomain[] pds = new ProtectionDomain[] {callerPd};
  15.423 +        return new AccessControlContext(combiner.combine(pds, null), combiner);
  15.424 +    }
  15.425 +
  15.426 +
  15.427 +    /**
  15.428 +     * Performs the specified <code>PrivilegedExceptionAction</code> with
  15.429 +     * privileges enabled and restricted by the specified
  15.430 +     * <code>AccessControlContext</code>.  The action is performed with the
  15.431 +     * intersection of the permissions possessed by the caller's
  15.432 +     * protection domain, and those possessed by the domains represented by the
  15.433 +     * specified <code>AccessControlContext</code>.
  15.434 +     * <p>
  15.435 +     * If the action's <code>run</code> method throws an <i>unchecked</i>
  15.436 +     * exception, it will propagate through this method.
  15.437 +     *
  15.438 +     * @param action the action to be performed
  15.439 +     * @param context an <i>access control context</i>
  15.440 +     *                representing the restriction to be applied to the
  15.441 +     *                caller's domain's privileges before performing
  15.442 +     *                the specified action.  If the context is
  15.443 +     *                <code>null</code>,
  15.444 +     *                then no additional restriction is applied.
  15.445 +     *
  15.446 +     * @return the value returned by the action's <code>run</code> method
  15.447 +     *
  15.448 +     * @exception PrivilegedActionException if the specified action's
  15.449 +     *         <code>run</code> method
  15.450 +     *         threw a <i>checked</i> exception
  15.451 +     * @exception NullPointerException if the action is <code>null</code>
  15.452 +     *
  15.453 +     * @see #doPrivileged(PrivilegedAction)
  15.454 +     * @see #doPrivileged(PrivilegedExceptionAction,AccessControlContext)
  15.455 +     */
  15.456 +    public static native <T> T
  15.457 +        doPrivileged(PrivilegedExceptionAction<T> action,
  15.458 +                     AccessControlContext context)
  15.459 +        throws PrivilegedActionException;
  15.460 +
  15.461 +    /**
  15.462 +     * Returns the AccessControl context. i.e., it gets
  15.463 +     * the protection domains of all the callers on the stack,
  15.464 +     * starting at the first class with a non-null
  15.465 +     * ProtectionDomain.
  15.466 +     *
  15.467 +     * @return the access control context based on the current stack or
  15.468 +     *         null if there was only privileged system code.
  15.469 +     */
  15.470 +
  15.471 +    private static native AccessControlContext getStackAccessControlContext();
  15.472 +
  15.473 +    /**
  15.474 +     * Returns the "inherited" AccessControl context. This is the context
  15.475 +     * that existed when the thread was created. Package private so
  15.476 +     * AccessControlContext can use it.
  15.477 +     */
  15.478 +
  15.479 +    static native AccessControlContext getInheritedAccessControlContext();
  15.480 +
  15.481 +    /**
  15.482 +     * This method takes a "snapshot" of the current calling context, which
  15.483 +     * includes the current Thread's inherited AccessControlContext,
  15.484 +     * and places it in an AccessControlContext object. This context may then
  15.485 +     * be checked at a later point, possibly in another thread.
  15.486 +     *
  15.487 +     * @see AccessControlContext
  15.488 +     *
  15.489 +     * @return the AccessControlContext based on the current context.
  15.490 +     */
  15.491 +
  15.492 +    public static AccessControlContext getContext()
  15.493 +    {
  15.494 +        AccessControlContext acc = getStackAccessControlContext();
  15.495 +        if (acc == null) {
  15.496 +            // all we had was privileged system code. We don't want
  15.497 +            // to return null though, so we construct a real ACC.
  15.498 +            return new AccessControlContext(null, true);
  15.499 +        } else {
  15.500 +            return acc.optimize();
  15.501 +        }
  15.502 +    }
  15.503 +
  15.504 +    /**
  15.505 +     * Determines whether the access request indicated by the
  15.506 +     * specified permission should be allowed or denied, based on
  15.507 +     * the current AccessControlContext and security policy.
  15.508 +     * This method quietly returns if the access request
  15.509 +     * is permitted, or throws an AccessControlException otherwise. The
  15.510 +     * getPermission method of the AccessControlException returns the
  15.511 +     * <code>perm</code> Permission object instance.
  15.512 +     *
  15.513 +     * @param perm the requested permission.
  15.514 +     *
  15.515 +     * @exception AccessControlException if the specified permission
  15.516 +     *            is not permitted, based on the current security policy.
  15.517 +     * @exception NullPointerException if the specified permission
  15.518 +     *            is <code>null</code> and is checked based on the
  15.519 +     *            security policy currently in effect.
  15.520 +     */
  15.521 +
  15.522 +    public static void checkPermission(Permission perm)
  15.523 +                 throws AccessControlException
  15.524 +    {
  15.525 +        //System.err.println("checkPermission "+perm);
  15.526 +        //Thread.currentThread().dumpStack();
  15.527 +
  15.528 +        if (perm == null) {
  15.529 +            throw new NullPointerException("permission can't be null");
  15.530 +        }
  15.531 +
  15.532 +        AccessControlContext stack = getStackAccessControlContext();
  15.533 +        // if context is null, we had privileged system code on the stack.
  15.534 +        if (stack == null) {
  15.535 +            Debug debug = AccessControlContext.getDebug();
  15.536 +            boolean dumpDebug = false;
  15.537 +            if (debug != null) {
  15.538 +                dumpDebug = !Debug.isOn("codebase=");
  15.539 +                dumpDebug &= !Debug.isOn("permission=") ||
  15.540 +                    Debug.isOn("permission=" + perm.getClass().getCanonicalName());
  15.541 +            }
  15.542 +
  15.543 +            if (dumpDebug && Debug.isOn("stack")) {
  15.544 +                Thread.currentThread().dumpStack();
  15.545 +            }
  15.546 +
  15.547 +            if (dumpDebug && Debug.isOn("domain")) {
  15.548 +                debug.println("domain (context is null)");
  15.549 +            }
  15.550 +
  15.551 +            if (dumpDebug) {
  15.552 +                debug.println("access allowed "+perm);
  15.553 +            }
  15.554 +            return;
  15.555 +        }
  15.556 +
  15.557 +        AccessControlContext acc = stack.optimize();
  15.558 +        acc.checkPermission(perm);
  15.559 +    }
  15.560 +}
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedAction.java	Thu Oct 03 15:40:35 2013 +0200
    16.3 @@ -0,0 +1,56 @@
    16.4 +/*
    16.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
    16.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    16.7 + *
    16.8 + * This code is free software; you can redistribute it and/or modify it
    16.9 + * under the terms of the GNU General Public License version 2 only, as
   16.10 + * published by the Free Software Foundation.  Oracle designates this
   16.11 + * particular file as subject to the "Classpath" exception as provided
   16.12 + * by Oracle in the LICENSE file that accompanied this code.
   16.13 + *
   16.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   16.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   16.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   16.17 + * version 2 for more details (a copy is included in the LICENSE file that
   16.18 + * accompanied this code).
   16.19 + *
   16.20 + * You should have received a copy of the GNU General Public License version
   16.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   16.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   16.23 + *
   16.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   16.25 + * or visit www.oracle.com if you need additional information or have any
   16.26 + * questions.
   16.27 + */
   16.28 +
   16.29 +package java.security;
   16.30 +
   16.31 +
   16.32 +/**
   16.33 + * A computation to be performed with privileges enabled.  The computation is
   16.34 + * performed by invoking <code>AccessController.doPrivileged</code> on the
   16.35 + * <code>PrivilegedAction</code> object.  This interface is used only for
   16.36 + * computations that do not throw checked exceptions; computations that
   16.37 + * throw checked exceptions must use <code>PrivilegedExceptionAction</code>
   16.38 + * instead.
   16.39 + *
   16.40 + * @see AccessController
   16.41 + * @see AccessController#doPrivileged(PrivilegedAction)
   16.42 + * @see PrivilegedExceptionAction
   16.43 + */
   16.44 +
   16.45 +public interface PrivilegedAction<T> {
   16.46 +    /**
   16.47 +     * Performs the computation.  This method will be called by
   16.48 +     * <code>AccessController.doPrivileged</code> after enabling privileges.
   16.49 +     *
   16.50 +     * @return a class-dependent value that may represent the results of the
   16.51 +     *         computation. Each class that implements
   16.52 +     *         <code>PrivilegedAction</code>
   16.53 +     *         should document what (if anything) this value represents.
   16.54 +     * @see AccessController#doPrivileged(PrivilegedAction)
   16.55 +     * @see AccessController#doPrivileged(PrivilegedAction,
   16.56 +     *                                     AccessControlContext)
   16.57 +     */
   16.58 +    T run();
   16.59 +}
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedActionException.java	Thu Oct 03 15:40:35 2013 +0200
    17.3 @@ -0,0 +1,105 @@
    17.4 +/*
    17.5 + * Copyright (c) 1998, 2001, Oracle and/or its affiliates. All rights reserved.
    17.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    17.7 + *
    17.8 + * This code is free software; you can redistribute it and/or modify it
    17.9 + * under the terms of the GNU General Public License version 2 only, as
   17.10 + * published by the Free Software Foundation.  Oracle designates this
   17.11 + * particular file as subject to the "Classpath" exception as provided
   17.12 + * by Oracle in the LICENSE file that accompanied this code.
   17.13 + *
   17.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   17.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   17.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   17.17 + * version 2 for more details (a copy is included in the LICENSE file that
   17.18 + * accompanied this code).
   17.19 + *
   17.20 + * You should have received a copy of the GNU General Public License version
   17.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   17.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   17.23 + *
   17.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   17.25 + * or visit www.oracle.com if you need additional information or have any
   17.26 + * questions.
   17.27 + */
   17.28 +
   17.29 +package java.security;
   17.30 +
   17.31 +/**
   17.32 + * This exception is thrown by
   17.33 + * <code>doPrivileged(PrivilegedExceptionAction)</code> and
   17.34 + * <code>doPrivileged(PrivilegedExceptionAction,
   17.35 + * AccessControlContext context)</code> to indicate
   17.36 + * that the action being performed threw a checked exception.  The exception
   17.37 + * thrown by the action can be obtained by calling the
   17.38 + * <code>getException</code> method.  In effect, an
   17.39 + * <code>PrivilegedActionException</code> is a "wrapper"
   17.40 + * for an exception thrown by a privileged action.
   17.41 + *
   17.42 + * <p>As of release 1.4, this exception has been retrofitted to conform to
   17.43 + * the general purpose exception-chaining mechanism.  The "exception thrown
   17.44 + * by the privileged computation" that is provided at construction time and
   17.45 + * accessed via the {@link #getException()} method is now known as the
   17.46 + * <i>cause</i>, and may be accessed via the {@link Throwable#getCause()}
   17.47 + * method, as well as the aforementioned "legacy method."
   17.48 + *
   17.49 + * @see PrivilegedExceptionAction
   17.50 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
   17.51 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
   17.52 + */
   17.53 +public class PrivilegedActionException extends Exception {
   17.54 +    // use serialVersionUID from JDK 1.2.2 for interoperability
   17.55 +    private static final long serialVersionUID = 4724086851538908602L;
   17.56 +
   17.57 +    /**
   17.58 +     * @serial
   17.59 +     */
   17.60 +    private Exception exception;
   17.61 +
   17.62 +    /**
   17.63 +     * Constructs a new PrivilegedActionException &quot;wrapping&quot;
   17.64 +     * the specific Exception.
   17.65 +     *
   17.66 +     * @param exception The exception thrown
   17.67 +     */
   17.68 +    public PrivilegedActionException(Exception exception) {
   17.69 +        super((Throwable)null);  // Disallow initCause
   17.70 +        this.exception = exception;
   17.71 +    }
   17.72 +
   17.73 +    /**
   17.74 +     * Returns the exception thrown by the privileged computation that
   17.75 +     * resulted in this <code>PrivilegedActionException</code>.
   17.76 +     *
   17.77 +     * <p>This method predates the general-purpose exception chaining facility.
   17.78 +     * The {@link Throwable#getCause()} method is now the preferred means of
   17.79 +     * obtaining this information.
   17.80 +     *
   17.81 +     * @return the exception thrown by the privileged computation that
   17.82 +     *         resulted in this <code>PrivilegedActionException</code>.
   17.83 +     * @see PrivilegedExceptionAction
   17.84 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction)
   17.85 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction,
   17.86 +     *                                            AccessControlContext)
   17.87 +     */
   17.88 +    public Exception getException() {
   17.89 +        return exception;
   17.90 +    }
   17.91 +
   17.92 +    /**
   17.93 +     * Returns the cause of this exception (the exception thrown by
   17.94 +     * the privileged computation that resulted in this
   17.95 +     * <code>PrivilegedActionException</code>).
   17.96 +     *
   17.97 +     * @return  the cause of this exception.
   17.98 +     * @since   1.4
   17.99 +     */
  17.100 +    public Throwable getCause() {
  17.101 +        return exception;
  17.102 +    }
  17.103 +
  17.104 +    public String toString() {
  17.105 +        String s = getClass().getName();
  17.106 +        return (exception != null) ? (s + ": " + exception.toString()) : s;
  17.107 +    }
  17.108 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/rt/emul/compact/src/main/java/java/security/PrivilegedExceptionAction.java	Thu Oct 03 15:40:35 2013 +0200
    18.3 @@ -0,0 +1,62 @@
    18.4 +/*
    18.5 + * Copyright (c) 1998, 2004, Oracle and/or its affiliates. All rights reserved.
    18.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    18.7 + *
    18.8 + * This code is free software; you can redistribute it and/or modify it
    18.9 + * under the terms of the GNU General Public License version 2 only, as
   18.10 + * published by the Free Software Foundation.  Oracle designates this
   18.11 + * particular file as subject to the "Classpath" exception as provided
   18.12 + * by Oracle in the LICENSE file that accompanied this code.
   18.13 + *
   18.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   18.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   18.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   18.17 + * version 2 for more details (a copy is included in the LICENSE file that
   18.18 + * accompanied this code).
   18.19 + *
   18.20 + * You should have received a copy of the GNU General Public License version
   18.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   18.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   18.23 + *
   18.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   18.25 + * or visit www.oracle.com if you need additional information or have any
   18.26 + * questions.
   18.27 + */
   18.28 +
   18.29 +package java.security;
   18.30 +
   18.31 +
   18.32 +/**
   18.33 + * A computation to be performed with privileges enabled, that throws one or
   18.34 + * more checked exceptions.  The computation is performed by invoking
   18.35 + * <code>AccessController.doPrivileged</code> on the
   18.36 + * <code>PrivilegedExceptionAction</code> object.  This interface is
   18.37 + * used only for computations that throw checked exceptions;
   18.38 + * computations that do not throw
   18.39 + * checked exceptions should use <code>PrivilegedAction</code> instead.
   18.40 + *
   18.41 + * @see AccessController
   18.42 + * @see AccessController#doPrivileged(PrivilegedExceptionAction)
   18.43 + * @see AccessController#doPrivileged(PrivilegedExceptionAction,
   18.44 + *                                              AccessControlContext)
   18.45 + * @see PrivilegedAction
   18.46 + */
   18.47 +
   18.48 +public interface PrivilegedExceptionAction<T> {
   18.49 +    /**
   18.50 +     * Performs the computation.  This method will be called by
   18.51 +     * <code>AccessController.doPrivileged</code> after enabling privileges.
   18.52 +     *
   18.53 +     * @return a class-dependent value that may represent the results of the
   18.54 +     *         computation.  Each class that implements
   18.55 +     *         <code>PrivilegedExceptionAction</code> should document what
   18.56 +     *         (if anything) this value represents.
   18.57 +     * @throws Exception an exceptional condition has occurred.  Each class
   18.58 +     *         that implements <code>PrivilegedExceptionAction</code> should
   18.59 +     *         document the exceptions that its run method can throw.
   18.60 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction)
   18.61 +     * @see AccessController#doPrivileged(PrivilegedExceptionAction,AccessControlContext)
   18.62 +     */
   18.63 +
   18.64 +    T run() throws Exception;
   18.65 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/rt/emul/compact/src/main/java/java/text/Annotation.java	Thu Oct 03 15:40:35 2013 +0200
    19.3 @@ -0,0 +1,84 @@
    19.4 +/*
    19.5 + * Copyright (c) 1997, 2002, Oracle and/or its affiliates. All rights reserved.
    19.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    19.7 + *
    19.8 + * This code is free software; you can redistribute it and/or modify it
    19.9 + * under the terms of the GNU General Public License version 2 only, as
   19.10 + * published by the Free Software Foundation.  Oracle designates this
   19.11 + * particular file as subject to the "Classpath" exception as provided
   19.12 + * by Oracle in the LICENSE file that accompanied this code.
   19.13 + *
   19.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   19.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   19.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   19.17 + * version 2 for more details (a copy is included in the LICENSE file that
   19.18 + * accompanied this code).
   19.19 + *
   19.20 + * You should have received a copy of the GNU General Public License version
   19.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   19.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   19.23 + *
   19.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   19.25 + * or visit www.oracle.com if you need additional information or have any
   19.26 + * questions.
   19.27 + */
   19.28 +
   19.29 +package java.text;
   19.30 +
   19.31 +/**
   19.32 +* An Annotation object is used as a wrapper for a text attribute value if
   19.33 +* the attribute has annotation characteristics. These characteristics are:
   19.34 +* <ul>
   19.35 +* <li>The text range that the attribute is applied to is critical to the
   19.36 +* semantics of the range. That means, the attribute cannot be applied to subranges
   19.37 +* of the text range that it applies to, and, if two adjacent text ranges have
   19.38 +* the same value for this attribute, the attribute still cannot be applied to
   19.39 +* the combined range as a whole with this value.
   19.40 +* <li>The attribute or its value usually do no longer apply if the underlying text is
   19.41 +* changed.
   19.42 +* </ul>
   19.43 +*
   19.44 +* An example is grammatical information attached to a sentence:
   19.45 +* For the previous sentence, you can say that "an example"
   19.46 +* is the subject, but you cannot say the same about "an", "example", or "exam".
   19.47 +* When the text is changed, the grammatical information typically becomes invalid.
   19.48 +* Another example is Japanese reading information (yomi).
   19.49 +*
   19.50 +* <p>
   19.51 +* Wrapping the attribute value into an Annotation object guarantees that
   19.52 +* adjacent text runs don't get merged even if the attribute values are equal,
   19.53 +* and indicates to text containers that the attribute should be discarded if
   19.54 +* the underlying text is modified.
   19.55 +*
   19.56 +* @see AttributedCharacterIterator
   19.57 +* @since 1.2
   19.58 +*/
   19.59 +
   19.60 +public class Annotation {
   19.61 +
   19.62 +    /**
   19.63 +     * Constructs an annotation record with the given value, which
   19.64 +     * may be null.
   19.65 +     * @param value The value of the attribute
   19.66 +     */
   19.67 +    public Annotation(Object value) {
   19.68 +        this.value = value;
   19.69 +    }
   19.70 +
   19.71 +    /**
   19.72 +     * Returns the value of the attribute, which may be null.
   19.73 +     */
   19.74 +    public Object getValue() {
   19.75 +        return value;
   19.76 +    }
   19.77 +
   19.78 +    /**
   19.79 +     * Returns the String representation of this Annotation.
   19.80 +     */
   19.81 +    public String toString() {
   19.82 +        return getClass().getName() + "[value=" + value + "]";
   19.83 +    }
   19.84 +
   19.85 +    private Object value;
   19.86 +
   19.87 +};
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedCharacterIterator.java	Thu Oct 03 15:40:35 2013 +0200
    20.3 @@ -0,0 +1,254 @@
    20.4 +/*
    20.5 + * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
    20.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    20.7 + *
    20.8 + * This code is free software; you can redistribute it and/or modify it
    20.9 + * under the terms of the GNU General Public License version 2 only, as
   20.10 + * published by the Free Software Foundation.  Oracle designates this
   20.11 + * particular file as subject to the "Classpath" exception as provided
   20.12 + * by Oracle in the LICENSE file that accompanied this code.
   20.13 + *
   20.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   20.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   20.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   20.17 + * version 2 for more details (a copy is included in the LICENSE file that
   20.18 + * accompanied this code).
   20.19 + *
   20.20 + * You should have received a copy of the GNU General Public License version
   20.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   20.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20.23 + *
   20.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   20.25 + * or visit www.oracle.com if you need additional information or have any
   20.26 + * questions.
   20.27 + */
   20.28 +
   20.29 +package java.text;
   20.30 +
   20.31 +import java.io.InvalidObjectException;
   20.32 +import java.io.Serializable;
   20.33 +import java.util.HashMap;
   20.34 +import java.util.Map;
   20.35 +import java.util.Set;
   20.36 +
   20.37 +/**
   20.38 + * An {@code AttributedCharacterIterator} allows iteration through both text and
   20.39 + * related attribute information.
   20.40 + *
   20.41 + * <p>
   20.42 + * An attribute is a key/value pair, identified by the key.  No two
   20.43 + * attributes on a given character can have the same key.
   20.44 + *
   20.45 + * <p>The values for an attribute are immutable, or must not be mutated
   20.46 + * by clients or storage.  They are always passed by reference, and not
   20.47 + * cloned.
   20.48 + *
   20.49 + * <p>A <em>run with respect to an attribute</em> is a maximum text range for
   20.50 + * which:
   20.51 + * <ul>
   20.52 + * <li>the attribute is undefined or {@code null} for the entire range, or
   20.53 + * <li>the attribute value is defined and has the same non-{@code null} value for the
   20.54 + *     entire range.
   20.55 + * </ul>
   20.56 + *
   20.57 + * <p>A <em>run with respect to a set of attributes</em> is a maximum text range for
   20.58 + * which this condition is met for each member attribute.
   20.59 + *
   20.60 + * <p>When getting a run with no explicit attributes specified (i.e.,
   20.61 + * calling {@link #getRunStart()} and {@link #getRunLimit()}), any
   20.62 + * contiguous text segments having the same attributes (the same set
   20.63 + * of attribute/value pairs) are treated as separate runs if the
   20.64 + * attributes have been given to those text segments separately.
   20.65 + *
   20.66 + * <p>The returned indexes are limited to the range of the iterator.
   20.67 + *
   20.68 + * <p>The returned attribute information is limited to runs that contain
   20.69 + * the current character.
   20.70 + *
   20.71 + * <p>
   20.72 + * Attribute keys are instances of {@link AttributedCharacterIterator.Attribute} and its
   20.73 + * subclasses, such as {@link java.awt.font.TextAttribute}.
   20.74 + *
   20.75 + * @see AttributedCharacterIterator.Attribute
   20.76 + * @see java.awt.font.TextAttribute
   20.77 + * @see AttributedString
   20.78 + * @see Annotation
   20.79 + * @since 1.2
   20.80 + */
   20.81 +
   20.82 +public interface AttributedCharacterIterator extends CharacterIterator {
   20.83 +
   20.84 +    /**
   20.85 +     * Defines attribute keys that are used to identify text attributes. These
   20.86 +     * keys are used in {@code AttributedCharacterIterator} and {@code AttributedString}.
   20.87 +     * @see AttributedCharacterIterator
   20.88 +     * @see AttributedString
   20.89 +     * @since 1.2
   20.90 +     */
   20.91 +
   20.92 +    public static class Attribute implements Serializable {
   20.93 +
   20.94 +        /**
   20.95 +         * The name of this {@code Attribute}. The name is used primarily by {@code readResolve}
   20.96 +         * to look up the corresponding predefined instance when deserializing
   20.97 +         * an instance.
   20.98 +         * @serial
   20.99 +         */
  20.100 +        private String name;
  20.101 +
  20.102 +        // table of all instances in this class, used by readResolve
  20.103 +        private static final Map instanceMap = new HashMap(7);
  20.104 +
  20.105 +        /**
  20.106 +         * Constructs an {@code Attribute} with the given name.
  20.107 +         */
  20.108 +        protected Attribute(String name) {
  20.109 +            this.name = name;
  20.110 +            if (this.getClass() == Attribute.class) {
  20.111 +                instanceMap.put(name, this);
  20.112 +            }
  20.113 +        }
  20.114 +
  20.115 +        /**
  20.116 +         * Compares two objects for equality. This version only returns true
  20.117 +         * for <code>x.equals(y)</code> if <code>x</code> and <code>y</code> refer
  20.118 +         * to the same object, and guarantees this for all subclasses.
  20.119 +         */
  20.120 +        public final boolean equals(Object obj) {
  20.121 +            return super.equals(obj);
  20.122 +        }
  20.123 +
  20.124 +        /**
  20.125 +         * Returns a hash code value for the object. This version is identical to
  20.126 +         * the one in {@code Object}, but is also final.
  20.127 +         */
  20.128 +        public final int hashCode() {
  20.129 +            return super.hashCode();
  20.130 +        }
  20.131 +
  20.132 +        /**
  20.133 +         * Returns a string representation of the object. This version returns the
  20.134 +         * concatenation of class name, {@code "("}, a name identifying the attribute
  20.135 +         * and {@code ")"}.
  20.136 +         */
  20.137 +        public String toString() {
  20.138 +            return getClass().getName() + "(" + name + ")";
  20.139 +        }
  20.140 +
  20.141 +        /**
  20.142 +         * Returns the name of the attribute.
  20.143 +         */
  20.144 +        protected String getName() {
  20.145 +            return name;
  20.146 +        }
  20.147 +
  20.148 +        /**
  20.149 +         * Resolves instances being deserialized to the predefined constants.
  20.150 +         */
  20.151 +        protected Object readResolve() throws InvalidObjectException {
  20.152 +            if (this.getClass() != Attribute.class) {
  20.153 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
  20.154 +            }
  20.155 +
  20.156 +            Attribute instance = (Attribute) instanceMap.get(getName());
  20.157 +            if (instance != null) {
  20.158 +                return instance;
  20.159 +            } else {
  20.160 +                throw new InvalidObjectException("unknown attribute name");
  20.161 +            }
  20.162 +        }
  20.163 +
  20.164 +        /**
  20.165 +         * Attribute key for the language of some text.
  20.166 +         * <p> Values are instances of {@link java.util.Locale Locale}.
  20.167 +         * @see java.util.Locale
  20.168 +         */
  20.169 +        public static final Attribute LANGUAGE = new Attribute("language");
  20.170 +
  20.171 +        /**
  20.172 +         * Attribute key for the reading of some text. In languages where the written form
  20.173 +         * and the pronunciation of a word are only loosely related (such as Japanese),
  20.174 +         * it is often necessary to store the reading (pronunciation) along with the
  20.175 +         * written form.
  20.176 +         * <p>Values are instances of {@link Annotation} holding instances of {@link String}.
  20.177 +         * @see Annotation
  20.178 +         * @see java.lang.String
  20.179 +         */
  20.180 +        public static final Attribute READING = new Attribute("reading");
  20.181 +
  20.182 +        /**
  20.183 +         * Attribute key for input method segments. Input methods often break
  20.184 +         * up text into segments, which usually correspond to words.
  20.185 +         * <p>Values are instances of {@link Annotation} holding a {@code null} reference.
  20.186 +         * @see Annotation
  20.187 +         */
  20.188 +        public static final Attribute INPUT_METHOD_SEGMENT = new Attribute("input_method_segment");
  20.189 +
  20.190 +        // make sure the serial version doesn't change between compiler versions
  20.191 +        private static final long serialVersionUID = -9142742483513960612L;
  20.192 +
  20.193 +    };
  20.194 +
  20.195 +    /**
  20.196 +     * Returns the index of the first character of the run
  20.197 +     * with respect to all attributes containing the current character.
  20.198 +     *
  20.199 +     * <p>Any contiguous text segments having the same attributes (the
  20.200 +     * same set of attribute/value pairs) are treated as separate runs
  20.201 +     * if the attributes have been given to those text segments separately.
  20.202 +     */
  20.203 +    public int getRunStart();
  20.204 +
  20.205 +    /**
  20.206 +     * Returns the index of the first character of the run
  20.207 +     * with respect to the given {@code attribute} containing the current character.
  20.208 +     */
  20.209 +    public int getRunStart(Attribute attribute);
  20.210 +
  20.211 +    /**
  20.212 +     * Returns the index of the first character of the run
  20.213 +     * with respect to the given {@code attributes} containing the current character.
  20.214 +     */
  20.215 +    public int getRunStart(Set<? extends Attribute> attributes);
  20.216 +
  20.217 +    /**
  20.218 +     * Returns the index of the first character following the run
  20.219 +     * with respect to all attributes containing the current character.
  20.220 +     *
  20.221 +     * <p>Any contiguous text segments having the same attributes (the
  20.222 +     * same set of attribute/value pairs) are treated as separate runs
  20.223 +     * if the attributes have been given to those text segments separately.
  20.224 +     */
  20.225 +    public int getRunLimit();
  20.226 +
  20.227 +    /**
  20.228 +     * Returns the index of the first character following the run
  20.229 +     * with respect to the given {@code attribute} containing the current character.
  20.230 +     */
  20.231 +    public int getRunLimit(Attribute attribute);
  20.232 +
  20.233 +    /**
  20.234 +     * Returns the index of the first character following the run
  20.235 +     * with respect to the given {@code attributes} containing the current character.
  20.236 +     */
  20.237 +    public int getRunLimit(Set<? extends Attribute> attributes);
  20.238 +
  20.239 +    /**
  20.240 +     * Returns a map with the attributes defined on the current
  20.241 +     * character.
  20.242 +     */
  20.243 +    public Map<Attribute,Object> getAttributes();
  20.244 +
  20.245 +    /**
  20.246 +     * Returns the value of the named {@code attribute} for the current character.
  20.247 +     * Returns {@code null} if the {@code attribute} is not defined.
  20.248 +     */
  20.249 +    public Object getAttribute(Attribute attribute);
  20.250 +
  20.251 +    /**
  20.252 +     * Returns the keys of all attributes defined on the
  20.253 +     * iterator's text range. The set is empty if no
  20.254 +     * attributes are defined.
  20.255 +     */
  20.256 +    public Set<Attribute> getAllAttributeKeys();
  20.257 +};
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/rt/emul/compact/src/main/java/java/text/AttributedString.java	Thu Oct 03 15:40:35 2013 +0200
    21.3 @@ -0,0 +1,1120 @@
    21.4 +/*
    21.5 + * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
    21.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    21.7 + *
    21.8 + * This code is free software; you can redistribute it and/or modify it
    21.9 + * under the terms of the GNU General Public License version 2 only, as
   21.10 + * published by the Free Software Foundation.  Oracle designates this
   21.11 + * particular file as subject to the "Classpath" exception as provided
   21.12 + * by Oracle in the LICENSE file that accompanied this code.
   21.13 + *
   21.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   21.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   21.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   21.17 + * version 2 for more details (a copy is included in the LICENSE file that
   21.18 + * accompanied this code).
   21.19 + *
   21.20 + * You should have received a copy of the GNU General Public License version
   21.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   21.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   21.23 + *
   21.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   21.25 + * or visit www.oracle.com if you need additional information or have any
   21.26 + * questions.
   21.27 + */
   21.28 +
   21.29 +package java.text;
   21.30 +
   21.31 +import java.util.*;
   21.32 +import java.text.AttributedCharacterIterator.Attribute;
   21.33 +
   21.34 +/**
   21.35 + * An AttributedString holds text and related attribute information. It
   21.36 + * may be used as the actual data storage in some cases where a text
   21.37 + * reader wants to access attributed text through the AttributedCharacterIterator
   21.38 + * interface.
   21.39 + *
   21.40 + * <p>
   21.41 + * An attribute is a key/value pair, identified by the key.  No two
   21.42 + * attributes on a given character can have the same key.
   21.43 + *
   21.44 + * <p>The values for an attribute are immutable, or must not be mutated
   21.45 + * by clients or storage.  They are always passed by reference, and not
   21.46 + * cloned.
   21.47 + *
   21.48 + * @see AttributedCharacterIterator
   21.49 + * @see Annotation
   21.50 + * @since 1.2
   21.51 + */
   21.52 +
   21.53 +public class AttributedString {
   21.54 +
   21.55 +    // since there are no vectors of int, we have to use arrays.
   21.56 +    // We allocate them in chunks of 10 elements so we don't have to allocate all the time.
   21.57 +    private static final int ARRAY_SIZE_INCREMENT = 10;
   21.58 +
   21.59 +    // field holding the text
   21.60 +    String text;
   21.61 +
   21.62 +    // fields holding run attribute information
   21.63 +    // run attributes are organized by run
   21.64 +    int runArraySize;               // current size of the arrays
   21.65 +    int runCount;                   // actual number of runs, <= runArraySize
   21.66 +    int runStarts[];                // start index for each run
   21.67 +    Vector runAttributes[];         // vector of attribute keys for each run
   21.68 +    Vector runAttributeValues[];    // parallel vector of attribute values for each run
   21.69 +
   21.70 +    /**
   21.71 +     * Constructs an AttributedString instance with the given
   21.72 +     * AttributedCharacterIterators.
   21.73 +     *
   21.74 +     * @param iterators AttributedCharacterIterators to construct
   21.75 +     * AttributedString from.
   21.76 +     * @throws NullPointerException if iterators is null
   21.77 +     */
   21.78 +    AttributedString(AttributedCharacterIterator[] iterators) {
   21.79 +        if (iterators == null) {
   21.80 +            throw new NullPointerException("Iterators must not be null");
   21.81 +        }
   21.82 +        if (iterators.length == 0) {
   21.83 +            text = "";
   21.84 +        }
   21.85 +        else {
   21.86 +            // Build the String contents
   21.87 +            StringBuffer buffer = new StringBuffer();
   21.88 +            for (int counter = 0; counter < iterators.length; counter++) {
   21.89 +                appendContents(buffer, iterators[counter]);
   21.90 +            }
   21.91 +
   21.92 +            text = buffer.toString();
   21.93 +
   21.94 +            if (text.length() > 0) {
   21.95 +                // Determine the runs, creating a new run when the attributes
   21.96 +                // differ.
   21.97 +                int offset = 0;
   21.98 +                Map last = null;
   21.99 +
  21.100 +                for (int counter = 0; counter < iterators.length; counter++) {
  21.101 +                    AttributedCharacterIterator iterator = iterators[counter];
  21.102 +                    int start = iterator.getBeginIndex();
  21.103 +                    int end = iterator.getEndIndex();
  21.104 +                    int index = start;
  21.105 +
  21.106 +                    while (index < end) {
  21.107 +                        iterator.setIndex(index);
  21.108 +
  21.109 +                        Map attrs = iterator.getAttributes();
  21.110 +
  21.111 +                        if (mapsDiffer(last, attrs)) {
  21.112 +                            setAttributes(attrs, index - start + offset);
  21.113 +                        }
  21.114 +                        last = attrs;
  21.115 +                        index = iterator.getRunLimit();
  21.116 +                    }
  21.117 +                    offset += (end - start);
  21.118 +                }
  21.119 +            }
  21.120 +        }
  21.121 +    }
  21.122 +
  21.123 +    /**
  21.124 +     * Constructs an AttributedString instance with the given text.
  21.125 +     * @param text The text for this attributed string.
  21.126 +     * @exception NullPointerException if <code>text</code> is null.
  21.127 +     */
  21.128 +    public AttributedString(String text) {
  21.129 +        if (text == null) {
  21.130 +            throw new NullPointerException();
  21.131 +        }
  21.132 +        this.text = text;
  21.133 +    }
  21.134 +
  21.135 +    /**
  21.136 +     * Constructs an AttributedString instance with the given text and attributes.
  21.137 +     * @param text The text for this attributed string.
  21.138 +     * @param attributes The attributes that apply to the entire string.
  21.139 +     * @exception NullPointerException if <code>text</code> or
  21.140 +     *            <code>attributes</code> is null.
  21.141 +     * @exception IllegalArgumentException if the text has length 0
  21.142 +     * and the attributes parameter is not an empty Map (attributes
  21.143 +     * cannot be applied to a 0-length range).
  21.144 +     */
  21.145 +    public AttributedString(String text,
  21.146 +                            Map<? extends Attribute, ?> attributes)
  21.147 +    {
  21.148 +        if (text == null || attributes == null) {
  21.149 +            throw new NullPointerException();
  21.150 +        }
  21.151 +        this.text = text;
  21.152 +
  21.153 +        if (text.length() == 0) {
  21.154 +            if (attributes.isEmpty())
  21.155 +                return;
  21.156 +            throw new IllegalArgumentException("Can't add attribute to 0-length text");
  21.157 +        }
  21.158 +
  21.159 +        int attributeCount = attributes.size();
  21.160 +        if (attributeCount > 0) {
  21.161 +            createRunAttributeDataVectors();
  21.162 +            Vector newRunAttributes = new Vector(attributeCount);
  21.163 +            Vector newRunAttributeValues = new Vector(attributeCount);
  21.164 +            runAttributes[0] = newRunAttributes;
  21.165 +            runAttributeValues[0] = newRunAttributeValues;
  21.166 +            Iterator iterator = attributes.entrySet().iterator();
  21.167 +            while (iterator.hasNext()) {
  21.168 +                Map.Entry entry = (Map.Entry) iterator.next();
  21.169 +                newRunAttributes.addElement(entry.getKey());
  21.170 +                newRunAttributeValues.addElement(entry.getValue());
  21.171 +            }
  21.172 +        }
  21.173 +    }
  21.174 +
  21.175 +    /**
  21.176 +     * Constructs an AttributedString instance with the given attributed
  21.177 +     * text represented by AttributedCharacterIterator.
  21.178 +     * @param text The text for this attributed string.
  21.179 +     * @exception NullPointerException if <code>text</code> is null.
  21.180 +     */
  21.181 +    public AttributedString(AttributedCharacterIterator text) {
  21.182 +        // If performance is critical, this constructor should be
  21.183 +        // implemented here rather than invoking the constructor for a
  21.184 +        // subrange. We can avoid some range checking in the loops.
  21.185 +        this(text, text.getBeginIndex(), text.getEndIndex(), null);
  21.186 +    }
  21.187 +
  21.188 +    /**
  21.189 +     * Constructs an AttributedString instance with the subrange of
  21.190 +     * the given attributed text represented by
  21.191 +     * AttributedCharacterIterator. If the given range produces an
  21.192 +     * empty text, all attributes will be discarded.  Note that any
  21.193 +     * attributes wrapped by an Annotation object are discarded for a
  21.194 +     * subrange of the original attribute range.
  21.195 +     *
  21.196 +     * @param text The text for this attributed string.
  21.197 +     * @param beginIndex Index of the first character of the range.
  21.198 +     * @param endIndex Index of the character following the last character
  21.199 +     * of the range.
  21.200 +     * @exception NullPointerException if <code>text</code> is null.
  21.201 +     * @exception IllegalArgumentException if the subrange given by
  21.202 +     * beginIndex and endIndex is out of the text range.
  21.203 +     * @see java.text.Annotation
  21.204 +     */
  21.205 +    public AttributedString(AttributedCharacterIterator text,
  21.206 +                            int beginIndex,
  21.207 +                            int endIndex) {
  21.208 +        this(text, beginIndex, endIndex, null);
  21.209 +    }
  21.210 +
  21.211 +    /**
  21.212 +     * Constructs an AttributedString instance with the subrange of
  21.213 +     * the given attributed text represented by
  21.214 +     * AttributedCharacterIterator.  Only attributes that match the
  21.215 +     * given attributes will be incorporated into the instance. If the
  21.216 +     * given range produces an empty text, all attributes will be
  21.217 +     * discarded. Note that any attributes wrapped by an Annotation
  21.218 +     * object are discarded for a subrange of the original attribute
  21.219 +     * range.
  21.220 +     *
  21.221 +     * @param text The text for this attributed string.
  21.222 +     * @param beginIndex Index of the first character of the range.
  21.223 +     * @param endIndex Index of the character following the last character
  21.224 +     * of the range.
  21.225 +     * @param attributes Specifies attributes to be extracted
  21.226 +     * from the text. If null is specified, all available attributes will
  21.227 +     * be used.
  21.228 +     * @exception NullPointerException if <code>text</code> is null.
  21.229 +     * @exception IllegalArgumentException if the subrange given by
  21.230 +     * beginIndex and endIndex is out of the text range.
  21.231 +     * @see java.text.Annotation
  21.232 +     */
  21.233 +    public AttributedString(AttributedCharacterIterator text,
  21.234 +                            int beginIndex,
  21.235 +                            int endIndex,
  21.236 +                            Attribute[] attributes) {
  21.237 +        if (text == null) {
  21.238 +            throw new NullPointerException();
  21.239 +        }
  21.240 +
  21.241 +        // Validate the given subrange
  21.242 +        int textBeginIndex = text.getBeginIndex();
  21.243 +        int textEndIndex = text.getEndIndex();
  21.244 +        if (beginIndex < textBeginIndex || endIndex > textEndIndex || beginIndex > endIndex)
  21.245 +            throw new IllegalArgumentException("Invalid substring range");
  21.246 +
  21.247 +        // Copy the given string
  21.248 +        StringBuffer textBuffer = new StringBuffer();
  21.249 +        text.setIndex(beginIndex);
  21.250 +        for (char c = text.current(); text.getIndex() < endIndex; c = text.next())
  21.251 +            textBuffer.append(c);
  21.252 +        this.text = textBuffer.toString();
  21.253 +
  21.254 +        if (beginIndex == endIndex)
  21.255 +            return;
  21.256 +
  21.257 +        // Select attribute keys to be taken care of
  21.258 +        HashSet keys = new HashSet();
  21.259 +        if (attributes == null) {
  21.260 +            keys.addAll(text.getAllAttributeKeys());
  21.261 +        } else {
  21.262 +            for (int i = 0; i < attributes.length; i++)
  21.263 +                keys.add(attributes[i]);
  21.264 +            keys.retainAll(text.getAllAttributeKeys());
  21.265 +        }
  21.266 +        if (keys.isEmpty())
  21.267 +            return;
  21.268 +
  21.269 +        // Get and set attribute runs for each attribute name. Need to
  21.270 +        // scan from the top of the text so that we can discard any
  21.271 +        // Annotation that is no longer applied to a subset text segment.
  21.272 +        Iterator itr = keys.iterator();
  21.273 +        while (itr.hasNext()) {
  21.274 +            Attribute attributeKey = (Attribute)itr.next();
  21.275 +            text.setIndex(textBeginIndex);
  21.276 +            while (text.getIndex() < endIndex) {
  21.277 +                int start = text.getRunStart(attributeKey);
  21.278 +                int limit = text.getRunLimit(attributeKey);
  21.279 +                Object value = text.getAttribute(attributeKey);
  21.280 +
  21.281 +                if (value != null) {
  21.282 +                    if (value instanceof Annotation) {
  21.283 +                        if (start >= beginIndex && limit <= endIndex) {
  21.284 +                            addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
  21.285 +                        } else {
  21.286 +                            if (limit > endIndex)
  21.287 +                                break;
  21.288 +                        }
  21.289 +                    } else {
  21.290 +                        // if the run is beyond the given (subset) range, we
  21.291 +                        // don't need to process further.
  21.292 +                        if (start >= endIndex)
  21.293 +                            break;
  21.294 +                        if (limit > beginIndex) {
  21.295 +                            // attribute is applied to any subrange
  21.296 +                            if (start < beginIndex)
  21.297 +                                start = beginIndex;
  21.298 +                            if (limit > endIndex)
  21.299 +                                limit = endIndex;
  21.300 +                            if (start != limit) {
  21.301 +                                addAttribute(attributeKey, value, start - beginIndex, limit - beginIndex);
  21.302 +                            }
  21.303 +                        }
  21.304 +                    }
  21.305 +                }
  21.306 +                text.setIndex(limit);
  21.307 +            }
  21.308 +        }
  21.309 +    }
  21.310 +
  21.311 +    /**
  21.312 +     * Adds an attribute to the entire string.
  21.313 +     * @param attribute the attribute key
  21.314 +     * @param value the value of the attribute; may be null
  21.315 +     * @exception NullPointerException if <code>attribute</code> is null.
  21.316 +     * @exception IllegalArgumentException if the AttributedString has length 0
  21.317 +     * (attributes cannot be applied to a 0-length range).
  21.318 +     */
  21.319 +    public void addAttribute(Attribute attribute, Object value) {
  21.320 +
  21.321 +        if (attribute == null) {
  21.322 +            throw new NullPointerException();
  21.323 +        }
  21.324 +
  21.325 +        int len = length();
  21.326 +        if (len == 0) {
  21.327 +            throw new IllegalArgumentException("Can't add attribute to 0-length text");
  21.328 +        }
  21.329 +
  21.330 +        addAttributeImpl(attribute, value, 0, len);
  21.331 +    }
  21.332 +
  21.333 +    /**
  21.334 +     * Adds an attribute to a subrange of the string.
  21.335 +     * @param attribute the attribute key
  21.336 +     * @param value The value of the attribute. May be null.
  21.337 +     * @param beginIndex Index of the first character of the range.
  21.338 +     * @param endIndex Index of the character following the last character of the range.
  21.339 +     * @exception NullPointerException if <code>attribute</code> is null.
  21.340 +     * @exception IllegalArgumentException if beginIndex is less then 0, endIndex is
  21.341 +     * greater than the length of the string, or beginIndex and endIndex together don't
  21.342 +     * define a non-empty subrange of the string.
  21.343 +     */
  21.344 +    public void addAttribute(Attribute attribute, Object value,
  21.345 +            int beginIndex, int endIndex) {
  21.346 +
  21.347 +        if (attribute == null) {
  21.348 +            throw new NullPointerException();
  21.349 +        }
  21.350 +
  21.351 +        if (beginIndex < 0 || endIndex > length() || beginIndex >= endIndex) {
  21.352 +            throw new IllegalArgumentException("Invalid substring range");
  21.353 +        }
  21.354 +
  21.355 +        addAttributeImpl(attribute, value, beginIndex, endIndex);
  21.356 +    }
  21.357 +
  21.358 +    /**
  21.359 +     * Adds a set of attributes to a subrange of the string.
  21.360 +     * @param attributes The attributes to be added to the string.
  21.361 +     * @param beginIndex Index of the first character of the range.
  21.362 +     * @param endIndex Index of the character following the last
  21.363 +     * character of the range.
  21.364 +     * @exception NullPointerException if <code>attributes</code> is null.
  21.365 +     * @exception IllegalArgumentException if beginIndex is less then
  21.366 +     * 0, endIndex is greater than the length of the string, or
  21.367 +     * beginIndex and endIndex together don't define a non-empty
  21.368 +     * subrange of the string and the attributes parameter is not an
  21.369 +     * empty Map.
  21.370 +     */
  21.371 +    public void addAttributes(Map<? extends Attribute, ?> attributes,
  21.372 +                              int beginIndex, int endIndex)
  21.373 +    {
  21.374 +        if (attributes == null) {
  21.375 +            throw new NullPointerException();
  21.376 +        }
  21.377 +
  21.378 +        if (beginIndex < 0 || endIndex > length() || beginIndex > endIndex) {
  21.379 +            throw new IllegalArgumentException("Invalid substring range");
  21.380 +        }
  21.381 +        if (beginIndex == endIndex) {
  21.382 +            if (attributes.isEmpty())
  21.383 +                return;
  21.384 +            throw new IllegalArgumentException("Can't add attribute to 0-length text");
  21.385 +        }
  21.386 +
  21.387 +        // make sure we have run attribute data vectors
  21.388 +        if (runCount == 0) {
  21.389 +            createRunAttributeDataVectors();
  21.390 +        }
  21.391 +
  21.392 +        // break up runs if necessary
  21.393 +        int beginRunIndex = ensureRunBreak(beginIndex);
  21.394 +        int endRunIndex = ensureRunBreak(endIndex);
  21.395 +
  21.396 +        Iterator iterator = attributes.entrySet().iterator();
  21.397 +        while (iterator.hasNext()) {
  21.398 +            Map.Entry entry = (Map.Entry) iterator.next();
  21.399 +            addAttributeRunData((Attribute) entry.getKey(), entry.getValue(), beginRunIndex, endRunIndex);
  21.400 +        }
  21.401 +    }
  21.402 +
  21.403 +    private synchronized void addAttributeImpl(Attribute attribute, Object value,
  21.404 +            int beginIndex, int endIndex) {
  21.405 +
  21.406 +        // make sure we have run attribute data vectors
  21.407 +        if (runCount == 0) {
  21.408 +            createRunAttributeDataVectors();
  21.409 +        }
  21.410 +
  21.411 +        // break up runs if necessary
  21.412 +        int beginRunIndex = ensureRunBreak(beginIndex);
  21.413 +        int endRunIndex = ensureRunBreak(endIndex);
  21.414 +
  21.415 +        addAttributeRunData(attribute, value, beginRunIndex, endRunIndex);
  21.416 +    }
  21.417 +
  21.418 +    private final void createRunAttributeDataVectors() {
  21.419 +        // use temporary variables so things remain consistent in case of an exception
  21.420 +        int newRunStarts[] = new int[ARRAY_SIZE_INCREMENT];
  21.421 +        Vector newRunAttributes[] = new Vector[ARRAY_SIZE_INCREMENT];
  21.422 +        Vector newRunAttributeValues[] = new Vector[ARRAY_SIZE_INCREMENT];
  21.423 +        runStarts = newRunStarts;
  21.424 +        runAttributes = newRunAttributes;
  21.425 +        runAttributeValues = newRunAttributeValues;
  21.426 +        runArraySize = ARRAY_SIZE_INCREMENT;
  21.427 +        runCount = 1; // assume initial run starting at index 0
  21.428 +    }
  21.429 +
  21.430 +    // ensure there's a run break at offset, return the index of the run
  21.431 +    private final int ensureRunBreak(int offset) {
  21.432 +        return ensureRunBreak(offset, true);
  21.433 +    }
  21.434 +
  21.435 +    /**
  21.436 +     * Ensures there is a run break at offset, returning the index of
  21.437 +     * the run. If this results in splitting a run, two things can happen:
  21.438 +     * <ul>
  21.439 +     * <li>If copyAttrs is true, the attributes from the existing run
  21.440 +     *     will be placed in both of the newly created runs.
  21.441 +     * <li>If copyAttrs is false, the attributes from the existing run
  21.442 +     * will NOT be copied to the run to the right (>= offset) of the break,
  21.443 +     * but will exist on the run to the left (< offset).
  21.444 +     * </ul>
  21.445 +     */
  21.446 +    private final int ensureRunBreak(int offset, boolean copyAttrs) {
  21.447 +        if (offset == length()) {
  21.448 +            return runCount;
  21.449 +        }
  21.450 +
  21.451 +        // search for the run index where this offset should be
  21.452 +        int runIndex = 0;
  21.453 +        while (runIndex < runCount && runStarts[runIndex] < offset) {
  21.454 +            runIndex++;
  21.455 +        }
  21.456 +
  21.457 +        // if the offset is at a run start already, we're done
  21.458 +        if (runIndex < runCount && runStarts[runIndex] == offset) {
  21.459 +            return runIndex;
  21.460 +        }
  21.461 +
  21.462 +        // we'll have to break up a run
  21.463 +        // first, make sure we have enough space in our arrays
  21.464 +        if (runCount == runArraySize) {
  21.465 +            int newArraySize = runArraySize + ARRAY_SIZE_INCREMENT;
  21.466 +            int newRunStarts[] = new int[newArraySize];
  21.467 +            Vector newRunAttributes[] = new Vector[newArraySize];
  21.468 +            Vector newRunAttributeValues[] = new Vector[newArraySize];
  21.469 +            for (int i = 0; i < runArraySize; i++) {
  21.470 +                newRunStarts[i] = runStarts[i];
  21.471 +                newRunAttributes[i] = runAttributes[i];
  21.472 +                newRunAttributeValues[i] = runAttributeValues[i];
  21.473 +            }
  21.474 +            runStarts = newRunStarts;
  21.475 +            runAttributes = newRunAttributes;
  21.476 +            runAttributeValues = newRunAttributeValues;
  21.477 +            runArraySize = newArraySize;
  21.478 +        }
  21.479 +
  21.480 +        // make copies of the attribute information of the old run that the new one used to be part of
  21.481 +        // use temporary variables so things remain consistent in case of an exception
  21.482 +        Vector newRunAttributes = null;
  21.483 +        Vector newRunAttributeValues = null;
  21.484 +
  21.485 +        if (copyAttrs) {
  21.486 +            Vector oldRunAttributes = runAttributes[runIndex - 1];
  21.487 +            Vector oldRunAttributeValues = runAttributeValues[runIndex - 1];
  21.488 +            if (oldRunAttributes != null) {
  21.489 +                newRunAttributes = (Vector) oldRunAttributes.clone();
  21.490 +            }
  21.491 +            if (oldRunAttributeValues != null) {
  21.492 +                newRunAttributeValues = (Vector) oldRunAttributeValues.clone();
  21.493 +            }
  21.494 +        }
  21.495 +
  21.496 +        // now actually break up the run
  21.497 +        runCount++;
  21.498 +        for (int i = runCount - 1; i > runIndex; i--) {
  21.499 +            runStarts[i] = runStarts[i - 1];
  21.500 +            runAttributes[i] = runAttributes[i - 1];
  21.501 +            runAttributeValues[i] = runAttributeValues[i - 1];
  21.502 +        }
  21.503 +        runStarts[runIndex] = offset;
  21.504 +        runAttributes[runIndex] = newRunAttributes;
  21.505 +        runAttributeValues[runIndex] = newRunAttributeValues;
  21.506 +
  21.507 +        return runIndex;
  21.508 +    }
  21.509 +
  21.510 +    // add the attribute attribute/value to all runs where beginRunIndex <= runIndex < endRunIndex
  21.511 +    private void addAttributeRunData(Attribute attribute, Object value,
  21.512 +            int beginRunIndex, int endRunIndex) {
  21.513 +
  21.514 +        for (int i = beginRunIndex; i < endRunIndex; i++) {
  21.515 +            int keyValueIndex = -1; // index of key and value in our vectors; assume we don't have an entry yet
  21.516 +            if (runAttributes[i] == null) {
  21.517 +                Vector newRunAttributes = new Vector();
  21.518 +                Vector newRunAttributeValues = new Vector();
  21.519 +                runAttributes[i] = newRunAttributes;
  21.520 +                runAttributeValues[i] = newRunAttributeValues;
  21.521 +            } else {
  21.522 +                // check whether we have an entry already
  21.523 +                keyValueIndex = runAttributes[i].indexOf(attribute);
  21.524 +            }
  21.525 +
  21.526 +            if (keyValueIndex == -1) {
  21.527 +                // create new entry
  21.528 +                int oldSize = runAttributes[i].size();
  21.529 +                runAttributes[i].addElement(attribute);
  21.530 +                try {
  21.531 +                    runAttributeValues[i].addElement(value);
  21.532 +                }
  21.533 +                catch (Exception e) {
  21.534 +                    runAttributes[i].setSize(oldSize);
  21.535 +                    runAttributeValues[i].setSize(oldSize);
  21.536 +                }
  21.537 +            } else {
  21.538 +                // update existing entry
  21.539 +                runAttributeValues[i].set(keyValueIndex, value);
  21.540 +            }
  21.541 +        }
  21.542 +    }
  21.543 +
  21.544 +    /**
  21.545 +     * Creates an AttributedCharacterIterator instance that provides access to the entire contents of
  21.546 +     * this string.
  21.547 +     *
  21.548 +     * @return An iterator providing access to the text and its attributes.
  21.549 +     */
  21.550 +    public AttributedCharacterIterator getIterator() {
  21.551 +        return getIterator(null, 0, length());
  21.552 +    }
  21.553 +
  21.554 +    /**
  21.555 +     * Creates an AttributedCharacterIterator instance that provides access to
  21.556 +     * selected contents of this string.
  21.557 +     * Information about attributes not listed in attributes that the
  21.558 +     * implementor may have need not be made accessible through the iterator.
  21.559 +     * If the list is null, all available attribute information should be made
  21.560 +     * accessible.
  21.561 +     *
  21.562 +     * @param attributes a list of attributes that the client is interested in
  21.563 +     * @return an iterator providing access to the entire text and its selected attributes
  21.564 +     */
  21.565 +    public AttributedCharacterIterator getIterator(Attribute[] attributes) {
  21.566 +        return getIterator(attributes, 0, length());
  21.567 +    }
  21.568 +
  21.569 +    /**
  21.570 +     * Creates an AttributedCharacterIterator instance that provides access to
  21.571 +     * selected contents of this string.
  21.572 +     * Information about attributes not listed in attributes that the
  21.573 +     * implementor may have need not be made accessible through the iterator.
  21.574 +     * If the list is null, all available attribute information should be made
  21.575 +     * accessible.
  21.576 +     *
  21.577 +     * @param attributes a list of attributes that the client is interested in
  21.578 +     * @param beginIndex the index of the first character
  21.579 +     * @param endIndex the index of the character following the last character
  21.580 +     * @return an iterator providing access to the text and its attributes
  21.581 +     * @exception IllegalArgumentException if beginIndex is less then 0,
  21.582 +     * endIndex is greater than the length of the string, or beginIndex is
  21.583 +     * greater than endIndex.
  21.584 +     */
  21.585 +    public AttributedCharacterIterator getIterator(Attribute[] attributes, int beginIndex, int endIndex) {
  21.586 +        return new AttributedStringIterator(attributes, beginIndex, endIndex);
  21.587 +    }
  21.588 +
  21.589 +    // all (with the exception of length) reading operations are private,
  21.590 +    // since AttributedString instances are accessed through iterators.
  21.591 +
  21.592 +    // length is package private so that CharacterIteratorFieldDelegate can
  21.593 +    // access it without creating an AttributedCharacterIterator.
  21.594 +    int length() {
  21.595 +        return text.length();
  21.596 +    }
  21.597 +
  21.598 +    private char charAt(int index) {
  21.599 +        return text.charAt(index);
  21.600 +    }
  21.601 +
  21.602 +    private synchronized Object getAttribute(Attribute attribute, int runIndex) {
  21.603 +        Vector currentRunAttributes = runAttributes[runIndex];
  21.604 +        Vector currentRunAttributeValues = runAttributeValues[runIndex];
  21.605 +        if (currentRunAttributes == null) {
  21.606 +            return null;
  21.607 +        }
  21.608 +        int attributeIndex = currentRunAttributes.indexOf(attribute);
  21.609 +        if (attributeIndex != -1) {
  21.610 +            return currentRunAttributeValues.elementAt(attributeIndex);
  21.611 +        }
  21.612 +        else {
  21.613 +            return null;
  21.614 +        }
  21.615 +    }
  21.616 +
  21.617 +    // gets an attribute value, but returns an annotation only if it's range does not extend outside the range beginIndex..endIndex
  21.618 +    private Object getAttributeCheckRange(Attribute attribute, int runIndex, int beginIndex, int endIndex) {
  21.619 +        Object value = getAttribute(attribute, runIndex);
  21.620 +        if (value instanceof Annotation) {
  21.621 +            // need to check whether the annotation's range extends outside the iterator's range
  21.622 +            if (beginIndex > 0) {
  21.623 +                int currIndex = runIndex;
  21.624 +                int runStart = runStarts[currIndex];
  21.625 +                while (runStart >= beginIndex &&
  21.626 +                        valuesMatch(value, getAttribute(attribute, currIndex - 1))) {
  21.627 +                    currIndex--;
  21.628 +                    runStart = runStarts[currIndex];
  21.629 +                }
  21.630 +                if (runStart < beginIndex) {
  21.631 +                    // annotation's range starts before iterator's range
  21.632 +                    return null;
  21.633 +                }
  21.634 +            }
  21.635 +            int textLength = length();
  21.636 +            if (endIndex < textLength) {
  21.637 +                int currIndex = runIndex;
  21.638 +                int runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
  21.639 +                while (runLimit <= endIndex &&
  21.640 +                        valuesMatch(value, getAttribute(attribute, currIndex + 1))) {
  21.641 +                    currIndex++;
  21.642 +                    runLimit = (currIndex < runCount - 1) ? runStarts[currIndex + 1] : textLength;
  21.643 +                }
  21.644 +                if (runLimit > endIndex) {
  21.645 +                    // annotation's range ends after iterator's range
  21.646 +                    return null;
  21.647 +                }
  21.648 +            }
  21.649 +            // annotation's range is subrange of iterator's range,
  21.650 +            // so we can return the value
  21.651 +        }
  21.652 +        return value;
  21.653 +    }
  21.654 +
  21.655 +    // returns whether all specified attributes have equal values in the runs with the given indices
  21.656 +    private boolean attributeValuesMatch(Set attributes, int runIndex1, int runIndex2) {
  21.657 +        Iterator iterator = attributes.iterator();
  21.658 +        while (iterator.hasNext()) {
  21.659 +            Attribute key = (Attribute) iterator.next();
  21.660 +           if (!valuesMatch(getAttribute(key, runIndex1), getAttribute(key, runIndex2))) {
  21.661 +                return false;
  21.662 +            }
  21.663 +        }
  21.664 +        return true;
  21.665 +    }
  21.666 +
  21.667 +    // returns whether the two objects are either both null or equal
  21.668 +    private final static boolean valuesMatch(Object value1, Object value2) {
  21.669 +        if (value1 == null) {
  21.670 +            return value2 == null;
  21.671 +        } else {
  21.672 +            return value1.equals(value2);
  21.673 +        }
  21.674 +    }
  21.675 +
  21.676 +    /**
  21.677 +     * Appends the contents of the CharacterIterator iterator into the
  21.678 +     * StringBuffer buf.
  21.679 +     */
  21.680 +    private final void appendContents(StringBuffer buf,
  21.681 +                                      CharacterIterator iterator) {
  21.682 +        int index = iterator.getBeginIndex();
  21.683 +        int end = iterator.getEndIndex();
  21.684 +
  21.685 +        while (index < end) {
  21.686 +            iterator.setIndex(index++);
  21.687 +            buf.append(iterator.current());
  21.688 +        }
  21.689 +    }
  21.690 +
  21.691 +    /**
  21.692 +     * Sets the attributes for the range from offset to the next run break
  21.693 +     * (typically the end of the text) to the ones specified in attrs.
  21.694 +     * This is only meant to be called from the constructor!
  21.695 +     */
  21.696 +    private void setAttributes(Map attrs, int offset) {
  21.697 +        if (runCount == 0) {
  21.698 +            createRunAttributeDataVectors();
  21.699 +        }
  21.700 +
  21.701 +        int index = ensureRunBreak(offset, false);
  21.702 +        int size;
  21.703 +
  21.704 +        if (attrs != null && (size = attrs.size()) > 0) {
  21.705 +            Vector runAttrs = new Vector(size);
  21.706 +            Vector runValues = new Vector(size);
  21.707 +            Iterator iterator = attrs.entrySet().iterator();
  21.708 +
  21.709 +            while (iterator.hasNext()) {
  21.710 +                Map.Entry entry = (Map.Entry)iterator.next();
  21.711 +
  21.712 +                runAttrs.add(entry.getKey());
  21.713 +                runValues.add(entry.getValue());
  21.714 +            }
  21.715 +            runAttributes[index] = runAttrs;
  21.716 +            runAttributeValues[index] = runValues;
  21.717 +        }
  21.718 +    }
  21.719 +
  21.720 +    /**
  21.721 +     * Returns true if the attributes specified in last and attrs differ.
  21.722 +     */
  21.723 +    private static boolean mapsDiffer(Map last, Map attrs) {
  21.724 +        if (last == null) {
  21.725 +            return (attrs != null && attrs.size() > 0);
  21.726 +        }
  21.727 +        return (!last.equals(attrs));
  21.728 +    }
  21.729 +
  21.730 +
  21.731 +    // the iterator class associated with this string class
  21.732 +
  21.733 +    final private class AttributedStringIterator implements AttributedCharacterIterator {
  21.734 +
  21.735 +        // note on synchronization:
  21.736 +        // we don't synchronize on the iterator, assuming that an iterator is only used in one thread.
  21.737 +        // we do synchronize access to the AttributedString however, since it's more likely to be shared between threads.
  21.738 +
  21.739 +        // start and end index for our iteration
  21.740 +        private int beginIndex;
  21.741 +        private int endIndex;
  21.742 +
  21.743 +        // attributes that our client is interested in
  21.744 +        private Attribute[] relevantAttributes;
  21.745 +
  21.746 +        // the current index for our iteration
  21.747 +        // invariant: beginIndex <= currentIndex <= endIndex
  21.748 +        private int currentIndex;
  21.749 +
  21.750 +        // information about the run that includes currentIndex
  21.751 +        private int currentRunIndex;
  21.752 +        private int currentRunStart;
  21.753 +        private int currentRunLimit;
  21.754 +
  21.755 +        // constructor
  21.756 +        AttributedStringIterator(Attribute[] attributes, int beginIndex, int endIndex) {
  21.757 +
  21.758 +            if (beginIndex < 0 || beginIndex > endIndex || endIndex > length()) {
  21.759 +                throw new IllegalArgumentException("Invalid substring range");
  21.760 +            }
  21.761 +
  21.762 +            this.beginIndex = beginIndex;
  21.763 +            this.endIndex = endIndex;
  21.764 +            this.currentIndex = beginIndex;
  21.765 +            updateRunInfo();
  21.766 +            if (attributes != null) {
  21.767 +                relevantAttributes = (Attribute[]) attributes.clone();
  21.768 +            }
  21.769 +        }
  21.770 +
  21.771 +        // Object methods. See documentation in that class.
  21.772 +
  21.773 +        public boolean equals(Object obj) {
  21.774 +            if (this == obj) {
  21.775 +                return true;
  21.776 +            }
  21.777 +            if (!(obj instanceof AttributedStringIterator)) {
  21.778 +                return false;
  21.779 +            }
  21.780 +
  21.781 +            AttributedStringIterator that = (AttributedStringIterator) obj;
  21.782 +
  21.783 +            if (AttributedString.this != that.getString())
  21.784 +                return false;
  21.785 +            if (currentIndex != that.currentIndex || beginIndex != that.beginIndex || endIndex != that.endIndex)
  21.786 +                return false;
  21.787 +            return true;
  21.788 +        }
  21.789 +
  21.790 +        public int hashCode() {
  21.791 +            return text.hashCode() ^ currentIndex ^ beginIndex ^ endIndex;
  21.792 +        }
  21.793 +
  21.794 +        public Object clone() {
  21.795 +            try {
  21.796 +                AttributedStringIterator other = (AttributedStringIterator) super.clone();
  21.797 +                return other;
  21.798 +            }
  21.799 +            catch (CloneNotSupportedException e) {
  21.800 +                throw new InternalError();
  21.801 +            }
  21.802 +        }
  21.803 +
  21.804 +        // CharacterIterator methods. See documentation in that interface.
  21.805 +
  21.806 +        public char first() {
  21.807 +            return internalSetIndex(beginIndex);
  21.808 +        }
  21.809 +
  21.810 +        public char last() {
  21.811 +            if (endIndex == beginIndex) {
  21.812 +                return internalSetIndex(endIndex);
  21.813 +            } else {
  21.814 +                return internalSetIndex(endIndex - 1);
  21.815 +            }
  21.816 +        }
  21.817 +
  21.818 +        public char current() {
  21.819 +            if (currentIndex == endIndex) {
  21.820 +                return DONE;
  21.821 +            } else {
  21.822 +                return charAt(currentIndex);
  21.823 +            }
  21.824 +        }
  21.825 +
  21.826 +        public char next() {
  21.827 +            if (currentIndex < endIndex) {
  21.828 +                return internalSetIndex(currentIndex + 1);
  21.829 +            }
  21.830 +            else {
  21.831 +                return DONE;
  21.832 +            }
  21.833 +        }
  21.834 +
  21.835 +        public char previous() {
  21.836 +            if (currentIndex > beginIndex) {
  21.837 +                return internalSetIndex(currentIndex - 1);
  21.838 +            }
  21.839 +            else {
  21.840 +                return DONE;
  21.841 +            }
  21.842 +        }
  21.843 +
  21.844 +        public char setIndex(int position) {
  21.845 +            if (position < beginIndex || position > endIndex)
  21.846 +                throw new IllegalArgumentException("Invalid index");
  21.847 +            return internalSetIndex(position);
  21.848 +        }
  21.849 +
  21.850 +        public int getBeginIndex() {
  21.851 +            return beginIndex;
  21.852 +        }
  21.853 +
  21.854 +        public int getEndIndex() {
  21.855 +            return endIndex;
  21.856 +        }
  21.857 +
  21.858 +        public int getIndex() {
  21.859 +            return currentIndex;
  21.860 +        }
  21.861 +
  21.862 +        // AttributedCharacterIterator methods. See documentation in that interface.
  21.863 +
  21.864 +        public int getRunStart() {
  21.865 +            return currentRunStart;
  21.866 +        }
  21.867 +
  21.868 +        public int getRunStart(Attribute attribute) {
  21.869 +            if (currentRunStart == beginIndex || currentRunIndex == -1) {
  21.870 +                return currentRunStart;
  21.871 +            } else {
  21.872 +                Object value = getAttribute(attribute);
  21.873 +                int runStart = currentRunStart;
  21.874 +                int runIndex = currentRunIndex;
  21.875 +                while (runStart > beginIndex &&
  21.876 +                        valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex - 1))) {
  21.877 +                    runIndex--;
  21.878 +                    runStart = runStarts[runIndex];
  21.879 +                }
  21.880 +                if (runStart < beginIndex) {
  21.881 +                    runStart = beginIndex;
  21.882 +                }
  21.883 +                return runStart;
  21.884 +            }
  21.885 +        }
  21.886 +
  21.887 +        public int getRunStart(Set<? extends Attribute> attributes) {
  21.888 +            if (currentRunStart == beginIndex || currentRunIndex == -1) {
  21.889 +                return currentRunStart;
  21.890 +            } else {
  21.891 +                int runStart = currentRunStart;
  21.892 +                int runIndex = currentRunIndex;
  21.893 +                while (runStart > beginIndex &&
  21.894 +                        AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex - 1)) {
  21.895 +                    runIndex--;
  21.896 +                    runStart = runStarts[runIndex];
  21.897 +                }
  21.898 +                if (runStart < beginIndex) {
  21.899 +                    runStart = beginIndex;
  21.900 +                }
  21.901 +                return runStart;
  21.902 +            }
  21.903 +        }
  21.904 +
  21.905 +        public int getRunLimit() {
  21.906 +            return currentRunLimit;
  21.907 +        }
  21.908 +
  21.909 +        public int getRunLimit(Attribute attribute) {
  21.910 +            if (currentRunLimit == endIndex || currentRunIndex == -1) {
  21.911 +                return currentRunLimit;
  21.912 +            } else {
  21.913 +                Object value = getAttribute(attribute);
  21.914 +                int runLimit = currentRunLimit;
  21.915 +                int runIndex = currentRunIndex;
  21.916 +                while (runLimit < endIndex &&
  21.917 +                        valuesMatch(value, AttributedString.this.getAttribute(attribute, runIndex + 1))) {
  21.918 +                    runIndex++;
  21.919 +                    runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
  21.920 +                }
  21.921 +                if (runLimit > endIndex) {
  21.922 +                    runLimit = endIndex;
  21.923 +                }
  21.924 +                return runLimit;
  21.925 +            }
  21.926 +        }
  21.927 +
  21.928 +        public int getRunLimit(Set<? extends Attribute> attributes) {
  21.929 +            if (currentRunLimit == endIndex || currentRunIndex == -1) {
  21.930 +                return currentRunLimit;
  21.931 +            } else {
  21.932 +                int runLimit = currentRunLimit;
  21.933 +                int runIndex = currentRunIndex;
  21.934 +                while (runLimit < endIndex &&
  21.935 +                        AttributedString.this.attributeValuesMatch(attributes, currentRunIndex, runIndex + 1)) {
  21.936 +                    runIndex++;
  21.937 +                    runLimit = runIndex < runCount - 1 ? runStarts[runIndex + 1] : endIndex;
  21.938 +                }
  21.939 +                if (runLimit > endIndex) {
  21.940 +                    runLimit = endIndex;
  21.941 +                }
  21.942 +                return runLimit;
  21.943 +            }
  21.944 +        }
  21.945 +
  21.946 +        public Map<Attribute,Object> getAttributes() {
  21.947 +            if (runAttributes == null || currentRunIndex == -1 || runAttributes[currentRunIndex] == null) {
  21.948 +                // ??? would be nice to return null, but current spec doesn't allow it
  21.949 +                // returning Hashtable saves AttributeMap from dealing with emptiness
  21.950 +                return new Hashtable();
  21.951 +            }
  21.952 +            return new AttributeMap(currentRunIndex, beginIndex, endIndex);
  21.953 +        }
  21.954 +
  21.955 +        public Set<Attribute> getAllAttributeKeys() {
  21.956 +            // ??? This should screen out attribute keys that aren't relevant to the client
  21.957 +            if (runAttributes == null) {
  21.958 +                // ??? would be nice to return null, but current spec doesn't allow it
  21.959 +                // returning HashSet saves us from dealing with emptiness
  21.960 +                return new HashSet();
  21.961 +            }
  21.962 +            synchronized (AttributedString.this) {
  21.963 +                // ??? should try to create this only once, then update if necessary,
  21.964 +                // and give callers read-only view
  21.965 +                Set keys = new HashSet();
  21.966 +                int i = 0;
  21.967 +                while (i < runCount) {
  21.968 +                    if (runStarts[i] < endIndex && (i == runCount - 1 || runStarts[i + 1] > beginIndex)) {
  21.969 +                        Vector currentRunAttributes = runAttributes[i];
  21.970 +                        if (currentRunAttributes != null) {
  21.971 +                            int j = currentRunAttributes.size();
  21.972 +                            while (j-- > 0) {
  21.973 +                                keys.add(currentRunAttributes.get(j));
  21.974 +                            }
  21.975 +                        }
  21.976 +                    }
  21.977 +                    i++;
  21.978 +                }
  21.979 +                return keys;
  21.980 +            }
  21.981 +        }
  21.982 +
  21.983 +        public Object getAttribute(Attribute attribute) {
  21.984 +            int runIndex = currentRunIndex;
  21.985 +            if (runIndex < 0) {
  21.986 +                return null;
  21.987 +            }
  21.988 +            return AttributedString.this.getAttributeCheckRange(attribute, runIndex, beginIndex, endIndex);
  21.989 +        }
  21.990 +
  21.991 +        // internally used methods
  21.992 +
  21.993 +        private AttributedString getString() {
  21.994 +            return AttributedString.this;
  21.995 +        }
  21.996 +
  21.997 +        // set the current index, update information about the current run if necessary,
  21.998 +        // return the character at the current index
  21.999 +        private char internalSetIndex(int position) {
 21.1000 +            currentIndex = position;
 21.1001 +            if (position < currentRunStart || position >= currentRunLimit) {
 21.1002 +                updateRunInfo();
 21.1003 +            }
 21.1004 +            if (currentIndex == endIndex) {
 21.1005 +                return DONE;
 21.1006 +            } else {
 21.1007 +                return charAt(position);
 21.1008 +            }
 21.1009 +        }
 21.1010 +
 21.1011 +        // update the information about the current run
 21.1012 +        private void updateRunInfo() {
 21.1013 +            if (currentIndex == endIndex) {
 21.1014 +                currentRunStart = currentRunLimit = endIndex;
 21.1015 +                currentRunIndex = -1;
 21.1016 +            } else {
 21.1017 +                synchronized (AttributedString.this) {
 21.1018 +                    int runIndex = -1;
 21.1019 +                    while (runIndex < runCount - 1 && runStarts[runIndex + 1] <= currentIndex)
 21.1020 +                        runIndex++;
 21.1021 +                    currentRunIndex = runIndex;
 21.1022 +                    if (runIndex >= 0) {
 21.1023 +                        currentRunStart = runStarts[runIndex];
 21.1024 +                        if (currentRunStart < beginIndex)
 21.1025 +                            currentRunStart = beginIndex;
 21.1026 +                    }
 21.1027 +                    else {
 21.1028 +                        currentRunStart = beginIndex;
 21.1029 +                    }
 21.1030 +                    if (runIndex < runCount - 1) {
 21.1031 +                        currentRunLimit = runStarts[runIndex + 1];
 21.1032 +                        if (currentRunLimit > endIndex)
 21.1033 +                            currentRunLimit = endIndex;
 21.1034 +                    }
 21.1035 +                    else {
 21.1036 +                        currentRunLimit = endIndex;
 21.1037 +                    }
 21.1038 +                }
 21.1039 +            }
 21.1040 +        }
 21.1041 +
 21.1042 +    }
 21.1043 +
 21.1044 +    // the map class associated with this string class, giving access to the attributes of one run
 21.1045 +
 21.1046 +    final private class AttributeMap extends AbstractMap<Attribute,Object> {
 21.1047 +
 21.1048 +        int runIndex;
 21.1049 +        int beginIndex;
 21.1050 +        int endIndex;
 21.1051 +
 21.1052 +        AttributeMap(int runIndex, int beginIndex, int endIndex) {
 21.1053 +            this.runIndex = runIndex;
 21.1054 +            this.beginIndex = beginIndex;
 21.1055 +            this.endIndex = endIndex;
 21.1056 +        }
 21.1057 +
 21.1058 +        public Set entrySet() {
 21.1059 +            HashSet set = new HashSet();
 21.1060 +            synchronized (AttributedString.this) {
 21.1061 +                int size = runAttributes[runIndex].size();
 21.1062 +                for (int i = 0; i < size; i++) {
 21.1063 +                    Attribute key = (Attribute) runAttributes[runIndex].get(i);
 21.1064 +                    Object value = runAttributeValues[runIndex].get(i);
 21.1065 +                    if (value instanceof Annotation) {
 21.1066 +                        value = AttributedString.this.getAttributeCheckRange(key,
 21.1067 +                                                             runIndex, beginIndex, endIndex);
 21.1068 +                        if (value == null) {
 21.1069 +                            continue;
 21.1070 +                        }
 21.1071 +                    }
 21.1072 +                    Map.Entry entry = new AttributeEntry(key, value);
 21.1073 +                    set.add(entry);
 21.1074 +                }
 21.1075 +            }
 21.1076 +            return set;
 21.1077 +        }
 21.1078 +
 21.1079 +        public Object get(Object key) {
 21.1080 +            return AttributedString.this.getAttributeCheckRange((Attribute) key, runIndex, beginIndex, endIndex);
 21.1081 +        }
 21.1082 +    }
 21.1083 +}
 21.1084 +
 21.1085 +class AttributeEntry implements Map.Entry {
 21.1086 +
 21.1087 +    private Attribute key;
 21.1088 +    private Object value;
 21.1089 +
 21.1090 +    AttributeEntry(Attribute key, Object value) {
 21.1091 +        this.key = key;
 21.1092 +        this.value = value;
 21.1093 +    }
 21.1094 +
 21.1095 +    public boolean equals(Object o) {
 21.1096 +        if (!(o instanceof AttributeEntry)) {
 21.1097 +            return false;
 21.1098 +        }
 21.1099 +        AttributeEntry other = (AttributeEntry) o;
 21.1100 +        return other.key.equals(key) &&
 21.1101 +            (value == null ? other.value == null : other.value.equals(value));
 21.1102 +    }
 21.1103 +
 21.1104 +    public Object getKey() {
 21.1105 +        return key;
 21.1106 +    }
 21.1107 +
 21.1108 +    public Object getValue() {
 21.1109 +        return value;
 21.1110 +    }
 21.1111 +
 21.1112 +    public Object setValue(Object newValue) {
 21.1113 +        throw new UnsupportedOperationException();
 21.1114 +    }
 21.1115 +
 21.1116 +    public int hashCode() {
 21.1117 +        return key.hashCode() ^ (value==null ? 0 : value.hashCode());
 21.1118 +    }
 21.1119 +
 21.1120 +    public String toString() {
 21.1121 +        return key.toString()+"="+value.toString();
 21.1122 +    }
 21.1123 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/rt/emul/compact/src/main/java/java/text/CalendarBuilder.java	Thu Oct 03 15:40:35 2013 +0200
    22.3 @@ -0,0 +1,170 @@
    22.4 +/*
    22.5 + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
    22.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    22.7 + *
    22.8 + * This code is free software; you can redistribute it and/or modify it
    22.9 + * under the terms of the GNU General Public License version 2 only, as
   22.10 + * published by the Free Software Foundation.  Oracle designates this
   22.11 + * particular file as subject to the "Classpath" exception as provided
   22.12 + * by Oracle in the LICENSE file that accompanied this code.
   22.13 + *
   22.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   22.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   22.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   22.17 + * version 2 for more details (a copy is included in the LICENSE file that
   22.18 + * accompanied this code).
   22.19 + *
   22.20 + * You should have received a copy of the GNU General Public License version
   22.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   22.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   22.23 + *
   22.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22.25 + * or visit www.oracle.com if you need additional information or have any
   22.26 + * questions.
   22.27 + */
   22.28 +
   22.29 +package java.text;
   22.30 +
   22.31 +import java.util.Calendar;
   22.32 +import static java.util.GregorianCalendar.*;
   22.33 +
   22.34 +/**
   22.35 + * {@code CalendarBuilder} keeps field-value pairs for setting
   22.36 + * the calendar fields of the given {@code Calendar}. It has the
   22.37 + * {@link Calendar#FIELD_COUNT FIELD_COUNT}-th field for the week year
   22.38 + * support. Also {@code ISO_DAY_OF_WEEK} is used to specify
   22.39 + * {@code DAY_OF_WEEK} in the ISO day of week numbering.
   22.40 + *
   22.41 + * <p>{@code CalendarBuilder} retains the semantic of the pseudo
   22.42 + * timestamp for fields. {@code CalendarBuilder} uses a single
   22.43 + * int array combining fields[] and stamp[] of {@code Calendar}.
   22.44 + *
   22.45 + * @author Masayoshi Okutsu
   22.46 + */
   22.47 +class CalendarBuilder {
   22.48 +    /*
   22.49 +     * Pseudo time stamp constants used in java.util.Calendar
   22.50 +     */
   22.51 +    private static final int UNSET = 0;
   22.52 +    private static final int COMPUTED = 1;
   22.53 +    private static final int MINIMUM_USER_STAMP = 2;
   22.54 +
   22.55 +    private static final int MAX_FIELD = FIELD_COUNT + 1;
   22.56 +
   22.57 +    public static final int WEEK_YEAR = FIELD_COUNT;
   22.58 +    public static final int ISO_DAY_OF_WEEK = 1000; // pseudo field index
   22.59 +
   22.60 +    // stamp[] (lower half) and field[] (upper half) combined
   22.61 +    private final int[] field;
   22.62 +    private int nextStamp;
   22.63 +    private int maxFieldIndex;
   22.64 +
   22.65 +    CalendarBuilder() {
   22.66 +        field = new int[MAX_FIELD * 2];
   22.67 +        nextStamp = MINIMUM_USER_STAMP;
   22.68 +        maxFieldIndex = -1;
   22.69 +    }
   22.70 +
   22.71 +    CalendarBuilder set(int index, int value) {
   22.72 +        if (index == ISO_DAY_OF_WEEK) {
   22.73 +            index = DAY_OF_WEEK;
   22.74 +            value = toCalendarDayOfWeek(value);
   22.75 +        }
   22.76 +        field[index] = nextStamp++;
   22.77 +        field[MAX_FIELD + index] = value;
   22.78 +        if (index > maxFieldIndex && index < FIELD_COUNT) {
   22.79 +            maxFieldIndex = index;
   22.80 +        }
   22.81 +        return this;
   22.82 +    }
   22.83 +
   22.84 +    CalendarBuilder addYear(int value) {
   22.85 +        field[MAX_FIELD + YEAR] += value;
   22.86 +        field[MAX_FIELD + WEEK_YEAR] += value;
   22.87 +        return this;
   22.88 +    }
   22.89 +
   22.90 +    boolean isSet(int index) {
   22.91 +        if (index == ISO_DAY_OF_WEEK) {
   22.92 +            index = DAY_OF_WEEK;
   22.93 +        }
   22.94 +        return field[index] > UNSET;
   22.95 +    }
   22.96 +
   22.97 +    Calendar establish(Calendar cal) {
   22.98 +        boolean weekDate = isSet(WEEK_YEAR)
   22.99 +                            && field[WEEK_YEAR] > field[YEAR];
  22.100 +        if (weekDate && !cal.isWeekDateSupported()) {
  22.101 +            // Use YEAR instead
  22.102 +            if (!isSet(YEAR)) {
  22.103 +                set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
  22.104 +            }
  22.105 +            weekDate = false;
  22.106 +        }
  22.107 +
  22.108 +        cal.clear();
  22.109 +        // Set the fields from the min stamp to the max stamp so that
  22.110 +        // the field resolution works in the Calendar.
  22.111 +        for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
  22.112 +            for (int index = 0; index <= maxFieldIndex; index++) {
  22.113 +                if (field[index] == stamp) {
  22.114 +                    cal.set(index, field[MAX_FIELD + index]);
  22.115 +                    break;
  22.116 +                }
  22.117 +            }
  22.118 +        }
  22.119 +
  22.120 +        if (weekDate) {
  22.121 +            int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
  22.122 +            int dayOfWeek = isSet(DAY_OF_WEEK) ?
  22.123 +                                field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
  22.124 +            if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
  22.125 +                if (dayOfWeek >= 8) {
  22.126 +                    dayOfWeek--;
  22.127 +                    weekOfYear += dayOfWeek / 7;
  22.128 +                    dayOfWeek = (dayOfWeek % 7) + 1;
  22.129 +                } else {
  22.130 +                    while (dayOfWeek <= 0) {
  22.131 +                        dayOfWeek += 7;
  22.132 +                        weekOfYear--;
  22.133 +                    }
  22.134 +                }
  22.135 +                dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
  22.136 +            }
  22.137 +            cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
  22.138 +        }
  22.139 +        return cal;
  22.140 +    }
  22.141 +
  22.142 +    public String toString() {
  22.143 +        StringBuilder sb = new StringBuilder();
  22.144 +        sb.append("CalendarBuilder:[");
  22.145 +        for (int i = 0; i < field.length; i++) {
  22.146 +            if (isSet(i)) {
  22.147 +                sb.append(i).append('=').append(field[MAX_FIELD + i]).append(',');
  22.148 +            }
  22.149 +        }
  22.150 +        int lastIndex = sb.length() - 1;
  22.151 +        if (sb.charAt(lastIndex) == ',') {
  22.152 +            sb.setLength(lastIndex);
  22.153 +        }
  22.154 +        sb.append(']');
  22.155 +        return sb.toString();
  22.156 +    }
  22.157 +
  22.158 +    static int toISODayOfWeek(int calendarDayOfWeek) {
  22.159 +        return calendarDayOfWeek == SUNDAY ? 7 : calendarDayOfWeek - 1;
  22.160 +    }
  22.161 +
  22.162 +    static int toCalendarDayOfWeek(int isoDayOfWeek) {
  22.163 +        if (!isValidDayOfWeek(isoDayOfWeek)) {
  22.164 +            // adjust later for lenient mode
  22.165 +            return isoDayOfWeek;
  22.166 +        }
  22.167 +        return isoDayOfWeek == 7 ? SUNDAY : isoDayOfWeek + 1;
  22.168 +    }
  22.169 +
  22.170 +    static boolean isValidDayOfWeek(int dayOfWeek) {
  22.171 +        return dayOfWeek > 0 && dayOfWeek <= 7;
  22.172 +    }
  22.173 +}
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIterator.java	Thu Oct 03 15:40:35 2013 +0200
    23.3 @@ -0,0 +1,193 @@
    23.4 +/*
    23.5 + * Copyright (c) 1996, 2000, Oracle and/or its affiliates. All rights reserved.
    23.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    23.7 + *
    23.8 + * This code is free software; you can redistribute it and/or modify it
    23.9 + * under the terms of the GNU General Public License version 2 only, as
   23.10 + * published by the Free Software Foundation.  Oracle designates this
   23.11 + * particular file as subject to the "Classpath" exception as provided
   23.12 + * by Oracle in the LICENSE file that accompanied this code.
   23.13 + *
   23.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   23.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   23.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   23.17 + * version 2 for more details (a copy is included in the LICENSE file that
   23.18 + * accompanied this code).
   23.19 + *
   23.20 + * You should have received a copy of the GNU General Public License version
   23.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   23.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   23.23 + *
   23.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   23.25 + * or visit www.oracle.com if you need additional information or have any
   23.26 + * questions.
   23.27 + */
   23.28 +
   23.29 +/*
   23.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   23.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   23.32 + *
   23.33 + * The original version of this source code and documentation
   23.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
   23.35 + * subsidiary of IBM. These materials are provided under terms
   23.36 + * of a License Agreement between Taligent and Sun. This technology
   23.37 + * is protected by multiple US and International patents.
   23.38 + *
   23.39 + * This notice and attribution to Taligent may not be removed.
   23.40 + * Taligent is a registered trademark of Taligent, Inc.
   23.41 + *
   23.42 + */
   23.43 +
   23.44 +package java.text;
   23.45 +
   23.46 +
   23.47 +/**
   23.48 + * This interface defines a protocol for bidirectional iteration over text.
   23.49 + * The iterator iterates over a bounded sequence of characters.  Characters
   23.50 + * are indexed with values beginning with the value returned by getBeginIndex() and
   23.51 + * continuing through the value returned by getEndIndex()-1.
   23.52 + * <p>
   23.53 + * Iterators maintain a current character index, whose valid range is from
   23.54 + * getBeginIndex() to getEndIndex(); the value getEndIndex() is included to allow
   23.55 + * handling of zero-length text ranges and for historical reasons.
   23.56 + * The current index can be retrieved by calling getIndex() and set directly
   23.57 + * by calling setIndex(), first(), and last().
   23.58 + * <p>
   23.59 + * The methods previous() and next() are used for iteration. They return DONE if
   23.60 + * they would move outside the range from getBeginIndex() to getEndIndex() -1,
   23.61 + * signaling that the iterator has reached the end of the sequence. DONE is
   23.62 + * also returned by other methods to indicate that the current index is
   23.63 + * outside this range.
   23.64 + *
   23.65 + * <P>Examples:<P>
   23.66 + *
   23.67 + * Traverse the text from start to finish
   23.68 + * <pre>
   23.69 + * public void traverseForward(CharacterIterator iter) {
   23.70 + *     for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) {
   23.71 + *         processChar(c);
   23.72 + *     }
   23.73 + * }
   23.74 + * </pre>
   23.75 + *
   23.76 + * Traverse the text backwards, from end to start
   23.77 + * <pre>
   23.78 + * public void traverseBackward(CharacterIterator iter) {
   23.79 + *     for(char c = iter.last(); c != CharacterIterator.DONE; c = iter.previous()) {
   23.80 + *         processChar(c);
   23.81 + *     }
   23.82 + * }
   23.83 + * </pre>
   23.84 + *
   23.85 + * Traverse both forward and backward from a given position in the text.
   23.86 + * Calls to notBoundary() in this example represents some
   23.87 + * additional stopping criteria.
   23.88 + * <pre>
   23.89 + * public void traverseOut(CharacterIterator iter, int pos) {
   23.90 + *     for (char c = iter.setIndex(pos);
   23.91 + *              c != CharacterIterator.DONE && notBoundary(c);
   23.92 + *              c = iter.next()) {
   23.93 + *     }
   23.94 + *     int end = iter.getIndex();
   23.95 + *     for (char c = iter.setIndex(pos);
   23.96 + *             c != CharacterIterator.DONE && notBoundary(c);
   23.97 + *             c = iter.previous()) {
   23.98 + *     }
   23.99 + *     int start = iter.getIndex();
  23.100 + *     processSection(start, end);
  23.101 + * }
  23.102 + * </pre>
  23.103 + *
  23.104 + * @see StringCharacterIterator
  23.105 + * @see AttributedCharacterIterator
  23.106 + */
  23.107 +
  23.108 +public interface CharacterIterator extends Cloneable
  23.109 +{
  23.110 +
  23.111 +    /**
  23.112 +     * Constant that is returned when the iterator has reached either the end
  23.113 +     * or the beginning of the text. The value is '\\uFFFF', the "not a
  23.114 +     * character" value which should not occur in any valid Unicode string.
  23.115 +     */
  23.116 +    public static final char DONE = '\uFFFF';
  23.117 +
  23.118 +    /**
  23.119 +     * Sets the position to getBeginIndex() and returns the character at that
  23.120 +     * position.
  23.121 +     * @return the first character in the text, or DONE if the text is empty
  23.122 +     * @see #getBeginIndex()
  23.123 +     */
  23.124 +    public char first();
  23.125 +
  23.126 +    /**
  23.127 +     * Sets the position to getEndIndex()-1 (getEndIndex() if the text is empty)
  23.128 +     * and returns the character at that position.
  23.129 +     * @return the last character in the text, or DONE if the text is empty
  23.130 +     * @see #getEndIndex()
  23.131 +     */
  23.132 +    public char last();
  23.133 +
  23.134 +    /**
  23.135 +     * Gets the character at the current position (as returned by getIndex()).
  23.136 +     * @return the character at the current position or DONE if the current
  23.137 +     * position is off the end of the text.
  23.138 +     * @see #getIndex()
  23.139 +     */
  23.140 +    public char current();
  23.141 +
  23.142 +    /**
  23.143 +     * Increments the iterator's index by one and returns the character
  23.144 +     * at the new index.  If the resulting index is greater or equal
  23.145 +     * to getEndIndex(), the current index is reset to getEndIndex() and
  23.146 +     * a value of DONE is returned.
  23.147 +     * @return the character at the new position or DONE if the new
  23.148 +     * position is off the end of the text range.
  23.149 +     */
  23.150 +    public char next();
  23.151 +
  23.152 +    /**
  23.153 +     * Decrements the iterator's index by one and returns the character
  23.154 +     * at the new index. If the current index is getBeginIndex(), the index
  23.155 +     * remains at getBeginIndex() and a value of DONE is returned.
  23.156 +     * @return the character at the new position or DONE if the current
  23.157 +     * position is equal to getBeginIndex().
  23.158 +     */
  23.159 +    public char previous();
  23.160 +
  23.161 +    /**
  23.162 +     * Sets the position to the specified position in the text and returns that
  23.163 +     * character.
  23.164 +     * @param position the position within the text.  Valid values range from
  23.165 +     * getBeginIndex() to getEndIndex().  An IllegalArgumentException is thrown
  23.166 +     * if an invalid value is supplied.
  23.167 +     * @return the character at the specified position or DONE if the specified position is equal to getEndIndex()
  23.168 +     */
  23.169 +    public char setIndex(int position);
  23.170 +
  23.171 +    /**
  23.172 +     * Returns the start index of the text.
  23.173 +     * @return the index at which the text begins.
  23.174 +     */
  23.175 +    public int getBeginIndex();
  23.176 +
  23.177 +    /**
  23.178 +     * Returns the end index of the text.  This index is the index of the first
  23.179 +     * character following the end of the text.
  23.180 +     * @return the index after the last character in the text
  23.181 +     */
  23.182 +    public int getEndIndex();
  23.183 +
  23.184 +    /**
  23.185 +     * Returns the current index.
  23.186 +     * @return the current index.
  23.187 +     */
  23.188 +    public int getIndex();
  23.189 +
  23.190 +    /**
  23.191 +     * Create a copy of this iterator
  23.192 +     * @return A copy of this
  23.193 +     */
  23.194 +    public Object clone();
  23.195 +
  23.196 +}
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/rt/emul/compact/src/main/java/java/text/CharacterIteratorFieldDelegate.java	Thu Oct 03 15:40:35 2013 +0200
    24.3 @@ -0,0 +1,124 @@
    24.4 +/*
    24.5 + * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved.
    24.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    24.7 + *
    24.8 + * This code is free software; you can redistribute it and/or modify it
    24.9 + * under the terms of the GNU General Public License version 2 only, as
   24.10 + * published by the Free Software Foundation.  Oracle designates this
   24.11 + * particular file as subject to the "Classpath" exception as provided
   24.12 + * by Oracle in the LICENSE file that accompanied this code.
   24.13 + *
   24.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   24.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   24.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   24.17 + * version 2 for more details (a copy is included in the LICENSE file that
   24.18 + * accompanied this code).
   24.19 + *
   24.20 + * You should have received a copy of the GNU General Public License version
   24.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   24.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   24.23 + *
   24.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   24.25 + * or visit www.oracle.com if you need additional information or have any
   24.26 + * questions.
   24.27 + */
   24.28 +package java.text;
   24.29 +
   24.30 +import java.util.ArrayList;
   24.31 +
   24.32 +/**
   24.33 + * CharacterIteratorFieldDelegate combines the notifications from a Format
   24.34 + * into a resulting <code>AttributedCharacterIterator</code>. The resulting
   24.35 + * <code>AttributedCharacterIterator</code> can be retrieved by way of
   24.36 + * the <code>getIterator</code> method.
   24.37 + *
   24.38 + */
   24.39 +class CharacterIteratorFieldDelegate implements Format.FieldDelegate {
   24.40 +    /**
   24.41 +     * Array of AttributeStrings. Whenever <code>formatted</code> is invoked
   24.42 +     * for a region > size, a new instance of AttributedString is added to
   24.43 +     * attributedStrings. Subsequent invocations of <code>formatted</code>
   24.44 +     * for existing regions result in invoking addAttribute on the existing
   24.45 +     * AttributedStrings.
   24.46 +     */
   24.47 +    private ArrayList attributedStrings;
   24.48 +    /**
   24.49 +     * Running count of the number of characters that have
   24.50 +     * been encountered.
   24.51 +     */
   24.52 +    private int size;
   24.53 +
   24.54 +
   24.55 +    CharacterIteratorFieldDelegate() {
   24.56 +        attributedStrings = new ArrayList();
   24.57 +    }
   24.58 +
   24.59 +    public void formatted(Format.Field attr, Object value, int start, int end,
   24.60 +                          StringBuffer buffer) {
   24.61 +        if (start != end) {
   24.62 +            if (start < size) {
   24.63 +                // Adjust attributes of existing runs
   24.64 +                int index = size;
   24.65 +                int asIndex = attributedStrings.size() - 1;
   24.66 +
   24.67 +                while (start < index) {
   24.68 +                    AttributedString as = (AttributedString)attributedStrings.
   24.69 +                                           get(asIndex--);
   24.70 +                    int newIndex = index - as.length();
   24.71 +                    int aStart = Math.max(0, start - newIndex);
   24.72 +
   24.73 +                    as.addAttribute(attr, value, aStart, Math.min(
   24.74 +                                    end - start, as.length() - aStart) +
   24.75 +                                    aStart);
   24.76 +                    index = newIndex;
   24.77 +                }
   24.78 +            }
   24.79 +            if (size < start) {
   24.80 +                // Pad attributes
   24.81 +                attributedStrings.add(new AttributedString(
   24.82 +                                          buffer.substring(size, start)));
   24.83 +                size = start;
   24.84 +            }
   24.85 +            if (size < end) {
   24.86 +                // Add new string
   24.87 +                int aStart = Math.max(start, size);
   24.88 +                AttributedString string = new AttributedString(
   24.89 +                                   buffer.substring(aStart, end));
   24.90 +
   24.91 +                string.addAttribute(attr, value);
   24.92 +                attributedStrings.add(string);
   24.93 +                size = end;
   24.94 +            }
   24.95 +        }
   24.96 +    }
   24.97 +
   24.98 +    public void formatted(int fieldID, Format.Field attr, Object value,
   24.99 +                          int start, int end, StringBuffer buffer) {
  24.100 +        formatted(attr, value, start, end, buffer);
  24.101 +    }
  24.102 +
  24.103 +    /**
  24.104 +     * Returns an <code>AttributedCharacterIterator</code> that can be used
  24.105 +     * to iterate over the resulting formatted String.
  24.106 +     *
  24.107 +     * @pararm string Result of formatting.
  24.108 +     */
  24.109 +    public AttributedCharacterIterator getIterator(String string) {
  24.110 +        // Add the last AttributedCharacterIterator if necessary
  24.111 +        // assert(size <= string.length());
  24.112 +        if (string.length() > size) {
  24.113 +            attributedStrings.add(new AttributedString(
  24.114 +                                  string.substring(size)));
  24.115 +            size = string.length();
  24.116 +        }
  24.117 +        int iCount = attributedStrings.size();
  24.118 +        AttributedCharacterIterator iterators[] = new
  24.119 +                                    AttributedCharacterIterator[iCount];
  24.120 +
  24.121 +        for (int counter = 0; counter < iCount; counter++) {
  24.122 +            iterators[counter] = ((AttributedString)attributedStrings.
  24.123 +                                  get(counter)).getIterator();
  24.124 +        }
  24.125 +        return new AttributedString(iterators).getIterator();
  24.126 +    }
  24.127 +}
    25.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    25.2 +++ b/rt/emul/compact/src/main/java/java/text/ChoiceFormat.java	Thu Oct 03 15:40:35 2013 +0200
    25.3 @@ -0,0 +1,619 @@
    25.4 +/*
    25.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
    25.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    25.7 + *
    25.8 + * This code is free software; you can redistribute it and/or modify it
    25.9 + * under the terms of the GNU General Public License version 2 only, as
   25.10 + * published by the Free Software Foundation.  Oracle designates this
   25.11 + * particular file as subject to the "Classpath" exception as provided
   25.12 + * by Oracle in the LICENSE file that accompanied this code.
   25.13 + *
   25.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   25.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   25.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   25.17 + * version 2 for more details (a copy is included in the LICENSE file that
   25.18 + * accompanied this code).
   25.19 + *
   25.20 + * You should have received a copy of the GNU General Public License version
   25.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   25.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   25.23 + *
   25.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   25.25 + * or visit www.oracle.com if you need additional information or have any
   25.26 + * questions.
   25.27 + */
   25.28 +
   25.29 +/*
   25.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   25.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   25.32 + *
   25.33 + *   The original version of this source code and documentation is copyrighted
   25.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   25.35 + * materials are provided under terms of a License Agreement between Taligent
   25.36 + * and Sun. This technology is protected by multiple US and International
   25.37 + * patents. This notice and attribution to Taligent may not be removed.
   25.38 + *   Taligent is a registered trademark of Taligent, Inc.
   25.39 + *
   25.40 + */
   25.41 +
   25.42 +package java.text;
   25.43 +
   25.44 +import java.io.InvalidObjectException;
   25.45 +import java.io.IOException;
   25.46 +import java.io.ObjectInputStream;
   25.47 +import java.util.Arrays;
   25.48 +
   25.49 +/**
   25.50 + * A <code>ChoiceFormat</code> allows you to attach a format to a range of numbers.
   25.51 + * It is generally used in a <code>MessageFormat</code> for handling plurals.
   25.52 + * The choice is specified with an ascending list of doubles, where each item
   25.53 + * specifies a half-open interval up to the next item:
   25.54 + * <blockquote>
   25.55 + * <pre>
   25.56 + * X matches j if and only if limit[j] &lt;= X &lt; limit[j+1]
   25.57 + * </pre>
   25.58 + * </blockquote>
   25.59 + * If there is no match, then either the first or last index is used, depending
   25.60 + * on whether the number (X) is too low or too high.  If the limit array is not
   25.61 + * in ascending order, the results of formatting will be incorrect.  ChoiceFormat
   25.62 + * also accepts <code>&#92;u221E</code> as equivalent to infinity(INF).
   25.63 + *
   25.64 + * <p>
   25.65 + * <strong>Note:</strong>
   25.66 + * <code>ChoiceFormat</code> differs from the other <code>Format</code>
   25.67 + * classes in that you create a <code>ChoiceFormat</code> object with a
   25.68 + * constructor (not with a <code>getInstance</code> style factory
   25.69 + * method). The factory methods aren't necessary because <code>ChoiceFormat</code>
   25.70 + * doesn't require any complex setup for a given locale. In fact,
   25.71 + * <code>ChoiceFormat</code> doesn't implement any locale specific behavior.
   25.72 + *
   25.73 + * <p>
   25.74 + * When creating a <code>ChoiceFormat</code>, you must specify an array of formats
   25.75 + * and an array of limits. The length of these arrays must be the same.
   25.76 + * For example,
   25.77 + * <ul>
   25.78 + * <li>
   25.79 + *     <em>limits</em> = {1,2,3,4,5,6,7}<br>
   25.80 + *     <em>formats</em> = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"}
   25.81 + * <li>
   25.82 + *     <em>limits</em> = {0, 1, ChoiceFormat.nextDouble(1)}<br>
   25.83 + *     <em>formats</em> = {"no files", "one file", "many files"}<br>
   25.84 + *     (<code>nextDouble</code> can be used to get the next higher double, to
   25.85 + *     make the half-open interval.)
   25.86 + * </ul>
   25.87 + *
   25.88 + * <p>
   25.89 + * Here is a simple example that shows formatting and parsing:
   25.90 + * <blockquote>
   25.91 + * <pre>
   25.92 + * double[] limits = {1,2,3,4,5,6,7};
   25.93 + * String[] dayOfWeekNames = {"Sun","Mon","Tue","Wed","Thur","Fri","Sat"};
   25.94 + * ChoiceFormat form = new ChoiceFormat(limits, dayOfWeekNames);
   25.95 + * ParsePosition status = new ParsePosition(0);
   25.96 + * for (double i = 0.0; i &lt;= 8.0; ++i) {
   25.97 + *     status.setIndex(0);
   25.98 + *     System.out.println(i + " -&gt; " + form.format(i) + " -&gt; "
   25.99 + *                              + form.parse(form.format(i),status));
  25.100 + * }
  25.101 + * </pre>
  25.102 + * </blockquote>
  25.103 + * Here is a more complex example, with a pattern format:
  25.104 + * <blockquote>
  25.105 + * <pre>
  25.106 + * double[] filelimits = {0,1,2};
  25.107 + * String[] filepart = {"are no files","is one file","are {2} files"};
  25.108 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
  25.109 + * Format[] testFormats = {fileform, null, NumberFormat.getInstance()};
  25.110 + * MessageFormat pattform = new MessageFormat("There {0} on {1}");
  25.111 + * pattform.setFormats(testFormats);
  25.112 + * Object[] testArgs = {null, "ADisk", null};
  25.113 + * for (int i = 0; i &lt; 4; ++i) {
  25.114 + *     testArgs[0] = new Integer(i);
  25.115 + *     testArgs[2] = testArgs[0];
  25.116 + *     System.out.println(pattform.format(testArgs));
  25.117 + * }
  25.118 + * </pre>
  25.119 + * </blockquote>
  25.120 + * <p>
  25.121 + * Specifying a pattern for ChoiceFormat objects is fairly straightforward.
  25.122 + * For example:
  25.123 + * <blockquote>
  25.124 + * <pre>
  25.125 + * ChoiceFormat fmt = new ChoiceFormat(
  25.126 + *      "-1#is negative| 0#is zero or fraction | 1#is one |1.0&lt;is 1+ |2#is two |2&lt;is more than 2.");
  25.127 + * System.out.println("Formatter Pattern : " + fmt.toPattern());
  25.128 + *
  25.129 + * System.out.println("Format with -INF : " + fmt.format(Double.NEGATIVE_INFINITY));
  25.130 + * System.out.println("Format with -1.0 : " + fmt.format(-1.0));
  25.131 + * System.out.println("Format with 0 : " + fmt.format(0));
  25.132 + * System.out.println("Format with 0.9 : " + fmt.format(0.9));
  25.133 + * System.out.println("Format with 1.0 : " + fmt.format(1));
  25.134 + * System.out.println("Format with 1.5 : " + fmt.format(1.5));
  25.135 + * System.out.println("Format with 2 : " + fmt.format(2));
  25.136 + * System.out.println("Format with 2.1 : " + fmt.format(2.1));
  25.137 + * System.out.println("Format with NaN : " + fmt.format(Double.NaN));
  25.138 + * System.out.println("Format with +INF : " + fmt.format(Double.POSITIVE_INFINITY));
  25.139 + * </pre>
  25.140 + * </blockquote>
  25.141 + * And the output result would be like the following:
  25.142 + * <blockquote>
  25.143 + * <pre>
  25.144 + *   Format with -INF : is negative
  25.145 + *   Format with -1.0 : is negative
  25.146 + *   Format with 0 : is zero or fraction
  25.147 + *   Format with 0.9 : is zero or fraction
  25.148 + *   Format with 1.0 : is one
  25.149 + *   Format with 1.5 : is 1+
  25.150 + *   Format with 2 : is two
  25.151 + *   Format with 2.1 : is more than 2.
  25.152 + *   Format with NaN : is negative
  25.153 + *   Format with +INF : is more than 2.
  25.154 + * </pre>
  25.155 + * </blockquote>
  25.156 + *
  25.157 + * <h4><a name="synchronization">Synchronization</a></h4>
  25.158 + *
  25.159 + * <p>
  25.160 + * Choice formats are not synchronized.
  25.161 + * It is recommended to create separate format instances for each thread.
  25.162 + * If multiple threads access a format concurrently, it must be synchronized
  25.163 + * externally.
  25.164 + *
  25.165 + *
  25.166 + * @see          DecimalFormat
  25.167 + * @see          MessageFormat
  25.168 + * @author       Mark Davis
  25.169 + */
  25.170 +public class ChoiceFormat extends NumberFormat {
  25.171 +
  25.172 +    // Proclaim serial compatibility with 1.1 FCS
  25.173 +    private static final long serialVersionUID = 1795184449645032964L;
  25.174 +
  25.175 +    /**
  25.176 +     * Sets the pattern.
  25.177 +     * @param newPattern See the class description.
  25.178 +     */
  25.179 +    public void applyPattern(String newPattern) {
  25.180 +        StringBuffer[] segments = new StringBuffer[2];
  25.181 +        for (int i = 0; i < segments.length; ++i) {
  25.182 +            segments[i] = new StringBuffer();
  25.183 +        }
  25.184 +        double[] newChoiceLimits = new double[30];
  25.185 +        String[] newChoiceFormats = new String[30];
  25.186 +        int count = 0;
  25.187 +        int part = 0;
  25.188 +        double startValue = 0;
  25.189 +        double oldStartValue = Double.NaN;
  25.190 +        boolean inQuote = false;
  25.191 +        for (int i = 0; i < newPattern.length(); ++i) {
  25.192 +            char ch = newPattern.charAt(i);
  25.193 +            if (ch=='\'') {
  25.194 +                // Check for "''" indicating a literal quote
  25.195 +                if ((i+1)<newPattern.length() && newPattern.charAt(i+1)==ch) {
  25.196 +                    segments[part].append(ch);
  25.197 +                    ++i;
  25.198 +                } else {
  25.199 +                    inQuote = !inQuote;
  25.200 +                }
  25.201 +            } else if (inQuote) {
  25.202 +                segments[part].append(ch);
  25.203 +            } else if (ch == '<' || ch == '#' || ch == '\u2264') {
  25.204 +                if (segments[0].length() == 0) {
  25.205 +                    throw new IllegalArgumentException();
  25.206 +                }
  25.207 +                try {
  25.208 +                    String tempBuffer = segments[0].toString();
  25.209 +                    if (tempBuffer.equals("\u221E")) {
  25.210 +                        startValue = Double.POSITIVE_INFINITY;
  25.211 +                    } else if (tempBuffer.equals("-\u221E")) {
  25.212 +                        startValue = Double.NEGATIVE_INFINITY;
  25.213 +                    } else {
  25.214 +                        startValue = Double.valueOf(segments[0].toString()).doubleValue();
  25.215 +                    }
  25.216 +                } catch (Exception e) {
  25.217 +                    throw new IllegalArgumentException();
  25.218 +                }
  25.219 +                if (ch == '<' && startValue != Double.POSITIVE_INFINITY &&
  25.220 +                        startValue != Double.NEGATIVE_INFINITY) {
  25.221 +                    startValue = nextDouble(startValue);
  25.222 +                }
  25.223 +                if (startValue <= oldStartValue) {
  25.224 +                    throw new IllegalArgumentException();
  25.225 +                }
  25.226 +                segments[0].setLength(0);
  25.227 +                part = 1;
  25.228 +            } else if (ch == '|') {
  25.229 +                if (count == newChoiceLimits.length) {
  25.230 +                    newChoiceLimits = doubleArraySize(newChoiceLimits);
  25.231 +                    newChoiceFormats = doubleArraySize(newChoiceFormats);
  25.232 +                }
  25.233 +                newChoiceLimits[count] = startValue;
  25.234 +                newChoiceFormats[count] = segments[1].toString();
  25.235 +                ++count;
  25.236 +                oldStartValue = startValue;
  25.237 +                segments[1].setLength(0);
  25.238 +                part = 0;
  25.239 +            } else {
  25.240 +                segments[part].append(ch);
  25.241 +            }
  25.242 +        }
  25.243 +        // clean up last one
  25.244 +        if (part == 1) {
  25.245 +            if (count == newChoiceLimits.length) {
  25.246 +                newChoiceLimits = doubleArraySize(newChoiceLimits);
  25.247 +                newChoiceFormats = doubleArraySize(newChoiceFormats);
  25.248 +            }
  25.249 +            newChoiceLimits[count] = startValue;
  25.250 +            newChoiceFormats[count] = segments[1].toString();
  25.251 +            ++count;
  25.252 +        }
  25.253 +        choiceLimits = new double[count];
  25.254 +        System.arraycopy(newChoiceLimits, 0, choiceLimits, 0, count);
  25.255 +        choiceFormats = new String[count];
  25.256 +        System.arraycopy(newChoiceFormats, 0, choiceFormats, 0, count);
  25.257 +    }
  25.258 +
  25.259 +    /**
  25.260 +     * Gets the pattern.
  25.261 +     */
  25.262 +    public String toPattern() {
  25.263 +        StringBuffer result = new StringBuffer();
  25.264 +        for (int i = 0; i < choiceLimits.length; ++i) {
  25.265 +            if (i != 0) {
  25.266 +                result.append('|');
  25.267 +            }
  25.268 +            // choose based upon which has less precision
  25.269 +            // approximate that by choosing the closest one to an integer.
  25.270 +            // could do better, but it's not worth it.
  25.271 +            double less = previousDouble(choiceLimits[i]);
  25.272 +            double tryLessOrEqual = Math.abs(Math.IEEEremainder(choiceLimits[i], 1.0d));
  25.273 +            double tryLess = Math.abs(Math.IEEEremainder(less, 1.0d));
  25.274 +
  25.275 +            if (tryLessOrEqual < tryLess) {
  25.276 +                result.append(""+choiceLimits[i]);
  25.277 +                result.append('#');
  25.278 +            } else {
  25.279 +                if (choiceLimits[i] == Double.POSITIVE_INFINITY) {
  25.280 +                    result.append("\u221E");
  25.281 +                } else if (choiceLimits[i] == Double.NEGATIVE_INFINITY) {
  25.282 +                    result.append("-\u221E");
  25.283 +                } else {
  25.284 +                    result.append(""+less);
  25.285 +                }
  25.286 +                result.append('<');
  25.287 +            }
  25.288 +            // Append choiceFormats[i], using quotes if there are special characters.
  25.289 +            // Single quotes themselves must be escaped in either case.
  25.290 +            String text = choiceFormats[i];
  25.291 +            boolean needQuote = text.indexOf('<') >= 0
  25.292 +                || text.indexOf('#') >= 0
  25.293 +                || text.indexOf('\u2264') >= 0
  25.294 +                || text.indexOf('|') >= 0;
  25.295 +            if (needQuote) result.append('\'');
  25.296 +            if (text.indexOf('\'') < 0) result.append(text);
  25.297 +            else {
  25.298 +                for (int j=0; j<text.length(); ++j) {
  25.299 +                    char c = text.charAt(j);
  25.300 +                    result.append(c);
  25.301 +                    if (c == '\'') result.append(c);
  25.302 +                }
  25.303 +            }
  25.304 +            if (needQuote) result.append('\'');
  25.305 +        }
  25.306 +        return result.toString();
  25.307 +    }
  25.308 +
  25.309 +    /**
  25.310 +     * Constructs with limits and corresponding formats based on the pattern.
  25.311 +     * @see #applyPattern
  25.312 +     */
  25.313 +    public ChoiceFormat(String newPattern)  {
  25.314 +        applyPattern(newPattern);
  25.315 +    }
  25.316 +
  25.317 +    /**
  25.318 +     * Constructs with the limits and the corresponding formats.
  25.319 +     * @see #setChoices
  25.320 +     */
  25.321 +    public ChoiceFormat(double[] limits, String[] formats) {
  25.322 +        setChoices(limits, formats);
  25.323 +    }
  25.324 +
  25.325 +    /**
  25.326 +     * Set the choices to be used in formatting.
  25.327 +     * @param limits contains the top value that you want
  25.328 +     * parsed with that format,and should be in ascending sorted order. When
  25.329 +     * formatting X, the choice will be the i, where
  25.330 +     * limit[i] &lt;= X &lt; limit[i+1].
  25.331 +     * If the limit array is not in ascending order, the results of formatting
  25.332 +     * will be incorrect.
  25.333 +     * @param formats are the formats you want to use for each limit.
  25.334 +     * They can be either Format objects or Strings.
  25.335 +     * When formatting with object Y,
  25.336 +     * if the object is a NumberFormat, then ((NumberFormat) Y).format(X)
  25.337 +     * is called. Otherwise Y.toString() is called.
  25.338 +     */
  25.339 +    public void setChoices(double[] limits, String formats[]) {
  25.340 +        if (limits.length != formats.length) {
  25.341 +            throw new IllegalArgumentException(
  25.342 +                "Array and limit arrays must be of the same length.");
  25.343 +        }
  25.344 +        choiceLimits = limits;
  25.345 +        choiceFormats = formats;
  25.346 +    }
  25.347 +
  25.348 +    /**
  25.349 +     * Get the limits passed in the constructor.
  25.350 +     * @return the limits.
  25.351 +     */
  25.352 +    public double[] getLimits() {
  25.353 +        return choiceLimits;
  25.354 +    }
  25.355 +
  25.356 +    /**
  25.357 +     * Get the formats passed in the constructor.
  25.358 +     * @return the formats.
  25.359 +     */
  25.360 +    public Object[] getFormats() {
  25.361 +        return choiceFormats;
  25.362 +    }
  25.363 +
  25.364 +    // Overrides
  25.365 +
  25.366 +    /**
  25.367 +     * Specialization of format. This method really calls
  25.368 +     * <code>format(double, StringBuffer, FieldPosition)</code>
  25.369 +     * thus the range of longs that are supported is only equal to
  25.370 +     * the range that can be stored by double. This will never be
  25.371 +     * a practical limitation.
  25.372 +     */
  25.373 +    public StringBuffer format(long number, StringBuffer toAppendTo,
  25.374 +                               FieldPosition status) {
  25.375 +        return format((double)number, toAppendTo, status);
  25.376 +    }
  25.377 +
  25.378 +    /**
  25.379 +     * Returns pattern with formatted double.
  25.380 +     * @param number number to be formatted & substituted.
  25.381 +     * @param toAppendTo where text is appended.
  25.382 +     * @param status ignore no useful status is returned.
  25.383 +     */
  25.384 +   public StringBuffer format(double number, StringBuffer toAppendTo,
  25.385 +                               FieldPosition status) {
  25.386 +        // find the number
  25.387 +        int i;
  25.388 +        for (i = 0; i < choiceLimits.length; ++i) {
  25.389 +            if (!(number >= choiceLimits[i])) {
  25.390 +                // same as number < choiceLimits, except catchs NaN
  25.391 +                break;
  25.392 +            }
  25.393 +        }
  25.394 +        --i;
  25.395 +        if (i < 0) i = 0;
  25.396 +        // return either a formatted number, or a string
  25.397 +        return toAppendTo.append(choiceFormats[i]);
  25.398 +    }
  25.399 +
  25.400 +    /**
  25.401 +     * Parses a Number from the input text.
  25.402 +     * @param text the source text.
  25.403 +     * @param status an input-output parameter.  On input, the
  25.404 +     * status.index field indicates the first character of the
  25.405 +     * source text that should be parsed.  On exit, if no error
  25.406 +     * occured, status.index is set to the first unparsed character
  25.407 +     * in the source text.  On exit, if an error did occur,
  25.408 +     * status.index is unchanged and status.errorIndex is set to the
  25.409 +     * first index of the character that caused the parse to fail.
  25.410 +     * @return A Number representing the value of the number parsed.
  25.411 +     */
  25.412 +    public Number parse(String text, ParsePosition status) {
  25.413 +        // find the best number (defined as the one with the longest parse)
  25.414 +        int start = status.index;
  25.415 +        int furthest = start;
  25.416 +        double bestNumber = Double.NaN;
  25.417 +        double tempNumber = 0.0;
  25.418 +        for (int i = 0; i < choiceFormats.length; ++i) {
  25.419 +            String tempString = choiceFormats[i];
  25.420 +            if (text.regionMatches(start, tempString, 0, tempString.length())) {
  25.421 +                status.index = start + tempString.length();
  25.422 +                tempNumber = choiceLimits[i];
  25.423 +                if (status.index > furthest) {
  25.424 +                    furthest = status.index;
  25.425 +                    bestNumber = tempNumber;
  25.426 +                    if (furthest == text.length()) break;
  25.427 +                }
  25.428 +            }
  25.429 +        }
  25.430 +        status.index = furthest;
  25.431 +        if (status.index == start) {
  25.432 +            status.errorIndex = furthest;
  25.433 +        }
  25.434 +        return new Double(bestNumber);
  25.435 +    }
  25.436 +
  25.437 +    /**
  25.438 +     * Finds the least double greater than d.
  25.439 +     * If NaN, returns same value.
  25.440 +     * <p>Used to make half-open intervals.
  25.441 +     * @see #previousDouble
  25.442 +     */
  25.443 +    public static final double nextDouble (double d) {
  25.444 +        return nextDouble(d,true);
  25.445 +    }
  25.446 +
  25.447 +    /**
  25.448 +     * Finds the greatest double less than d.
  25.449 +     * If NaN, returns same value.
  25.450 +     * @see #nextDouble
  25.451 +     */
  25.452 +    public static final double previousDouble (double d) {
  25.453 +        return nextDouble(d,false);
  25.454 +    }
  25.455 +
  25.456 +    /**
  25.457 +     * Overrides Cloneable
  25.458 +     */
  25.459 +    public Object clone()
  25.460 +    {
  25.461 +        ChoiceFormat other = (ChoiceFormat) super.clone();
  25.462 +        // for primitives or immutables, shallow clone is enough
  25.463 +        other.choiceLimits = (double[]) choiceLimits.clone();
  25.464 +        other.choiceFormats = (String[]) choiceFormats.clone();
  25.465 +        return other;
  25.466 +    }
  25.467 +
  25.468 +    /**
  25.469 +     * Generates a hash code for the message format object.
  25.470 +     */
  25.471 +    public int hashCode() {
  25.472 +        int result = choiceLimits.length;
  25.473 +        if (choiceFormats.length > 0) {
  25.474 +            // enough for reasonable distribution
  25.475 +            result ^= choiceFormats[choiceFormats.length-1].hashCode();
  25.476 +        }
  25.477 +        return result;
  25.478 +    }
  25.479 +
  25.480 +    /**
  25.481 +     * Equality comparision between two
  25.482 +     */
  25.483 +    public boolean equals(Object obj) {
  25.484 +        if (obj == null) return false;
  25.485 +        if (this == obj)                      // quick check
  25.486 +            return true;
  25.487 +        if (getClass() != obj.getClass())
  25.488 +            return false;
  25.489 +        ChoiceFormat other = (ChoiceFormat) obj;
  25.490 +        return (Arrays.equals(choiceLimits, other.choiceLimits)
  25.491 +             && Arrays.equals(choiceFormats, other.choiceFormats));
  25.492 +    }
  25.493 +
  25.494 +    /**
  25.495 +     * After reading an object from the input stream, do a simple verification
  25.496 +     * to maintain class invariants.
  25.497 +     * @throws InvalidObjectException if the objects read from the stream is invalid.
  25.498 +     */
  25.499 +    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  25.500 +        in.defaultReadObject();
  25.501 +        if (choiceLimits.length != choiceFormats.length) {
  25.502 +            throw new InvalidObjectException(
  25.503 +                    "limits and format arrays of different length.");
  25.504 +        }
  25.505 +    }
  25.506 +
  25.507 +    // ===============privates===========================
  25.508 +
  25.509 +    /**
  25.510 +     * A list of lower bounds for the choices.  The formatter will return
  25.511 +     * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
  25.512 +     * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
  25.513 +     * @serial
  25.514 +     */
  25.515 +    private double[] choiceLimits;
  25.516 +
  25.517 +    /**
  25.518 +     * A list of choice strings.  The formatter will return
  25.519 +     * <code>choiceFormats[i]</code> if the number being formatted is greater than or equal to
  25.520 +     * <code>choiceLimits[i]</code> and less than <code>choiceLimits[i+1]</code>.
  25.521 +     * @serial
  25.522 +     */
  25.523 +    private String[] choiceFormats;
  25.524 +
  25.525 +    /*
  25.526 +    static final long SIGN          = 0x8000000000000000L;
  25.527 +    static final long EXPONENT      = 0x7FF0000000000000L;
  25.528 +    static final long SIGNIFICAND   = 0x000FFFFFFFFFFFFFL;
  25.529 +
  25.530 +    private static double nextDouble (double d, boolean positive) {
  25.531 +        if (Double.isNaN(d) || Double.isInfinite(d)) {
  25.532 +                return d;
  25.533 +            }
  25.534 +        long bits = Double.doubleToLongBits(d);
  25.535 +        long significand = bits & SIGNIFICAND;
  25.536 +        if (bits < 0) {
  25.537 +            significand |= (SIGN | EXPONENT);
  25.538 +        }
  25.539 +        long exponent = bits & EXPONENT;
  25.540 +        if (positive) {
  25.541 +            significand += 1;
  25.542 +            // FIXME fix overflow & underflow
  25.543 +        } else {
  25.544 +            significand -= 1;
  25.545 +            // FIXME fix overflow & underflow
  25.546 +        }
  25.547 +        bits = exponent | (significand & ~EXPONENT);
  25.548 +        return Double.longBitsToDouble(bits);
  25.549 +    }
  25.550 +    */
  25.551 +
  25.552 +    static final long SIGN                = 0x8000000000000000L;
  25.553 +    static final long EXPONENT            = 0x7FF0000000000000L;
  25.554 +    static final long POSITIVEINFINITY    = 0x7FF0000000000000L;
  25.555 +
  25.556 +    /**
  25.557 +     * Finds the least double greater than d (if positive == true),
  25.558 +     * or the greatest double less than d (if positive == false).
  25.559 +     * If NaN, returns same value.
  25.560 +     *
  25.561 +     * Does not affect floating-point flags,
  25.562 +     * provided these member functions do not:
  25.563 +     *          Double.longBitsToDouble(long)
  25.564 +     *          Double.doubleToLongBits(double)
  25.565 +     *          Double.isNaN(double)
  25.566 +     */
  25.567 +    public static double nextDouble (double d, boolean positive) {
  25.568 +
  25.569 +        /* filter out NaN's */
  25.570 +        if (Double.isNaN(d)) {
  25.571 +            return d;
  25.572 +        }
  25.573 +
  25.574 +        /* zero's are also a special case */
  25.575 +        if (d == 0.0) {
  25.576 +            double smallestPositiveDouble = Double.longBitsToDouble(1L);
  25.577 +            if (positive) {
  25.578 +                return smallestPositiveDouble;
  25.579 +            } else {
  25.580 +                return -smallestPositiveDouble;
  25.581 +            }
  25.582 +        }
  25.583 +
  25.584 +        /* if entering here, d is a nonzero value */
  25.585 +
  25.586 +        /* hold all bits in a long for later use */
  25.587 +        long bits = Double.doubleToLongBits(d);
  25.588 +
  25.589 +        /* strip off the sign bit */
  25.590 +        long magnitude = bits & ~SIGN;
  25.591 +
  25.592 +        /* if next double away from zero, increase magnitude */
  25.593 +        if ((bits > 0) == positive) {
  25.594 +            if (magnitude != POSITIVEINFINITY) {
  25.595 +                magnitude += 1;
  25.596 +            }
  25.597 +        }
  25.598 +        /* else decrease magnitude */
  25.599 +        else {
  25.600 +            magnitude -= 1;
  25.601 +        }
  25.602 +
  25.603 +        /* restore sign bit and return */
  25.604 +        long signbit = bits & SIGN;
  25.605 +        return Double.longBitsToDouble (magnitude | signbit);
  25.606 +    }
  25.607 +
  25.608 +    private static double[] doubleArraySize(double[] array) {
  25.609 +        int oldSize = array.length;
  25.610 +        double[] newArray = new double[oldSize * 2];
  25.611 +        System.arraycopy(array, 0, newArray, 0, oldSize);
  25.612 +        return newArray;
  25.613 +    }
  25.614 +
  25.615 +    private String[] doubleArraySize(String[] array) {
  25.616 +        int oldSize = array.length;
  25.617 +        String[] newArray = new String[oldSize * 2];
  25.618 +        System.arraycopy(array, 0, newArray, 0, oldSize);
  25.619 +        return newArray;
  25.620 +    }
  25.621 +
  25.622 +}
    26.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    26.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormat.java	Thu Oct 03 15:40:35 2013 +0200
    26.3 @@ -0,0 +1,1030 @@
    26.4 +/*
    26.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
    26.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    26.7 + *
    26.8 + * This code is free software; you can redistribute it and/or modify it
    26.9 + * under the terms of the GNU General Public License version 2 only, as
   26.10 + * published by the Free Software Foundation.  Oracle designates this
   26.11 + * particular file as subject to the "Classpath" exception as provided
   26.12 + * by Oracle in the LICENSE file that accompanied this code.
   26.13 + *
   26.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   26.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   26.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   26.17 + * version 2 for more details (a copy is included in the LICENSE file that
   26.18 + * accompanied this code).
   26.19 + *
   26.20 + * You should have received a copy of the GNU General Public License version
   26.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   26.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   26.23 + *
   26.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   26.25 + * or visit www.oracle.com if you need additional information or have any
   26.26 + * questions.
   26.27 + */
   26.28 +
   26.29 +/*
   26.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   26.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   26.32 + *
   26.33 + *   The original version of this source code and documentation is copyrighted
   26.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   26.35 + * materials are provided under terms of a License Agreement between Taligent
   26.36 + * and Sun. This technology is protected by multiple US and International
   26.37 + * patents. This notice and attribution to Taligent may not be removed.
   26.38 + *   Taligent is a registered trademark of Taligent, Inc.
   26.39 + *
   26.40 + */
   26.41 +
   26.42 +package java.text;
   26.43 +
   26.44 +import java.io.InvalidObjectException;
   26.45 +import java.text.spi.DateFormatProvider;
   26.46 +import java.util.Calendar;
   26.47 +import java.util.Date;
   26.48 +import java.util.GregorianCalendar;
   26.49 +import java.util.HashMap;
   26.50 +import java.util.Locale;
   26.51 +import java.util.Map;
   26.52 +import java.util.MissingResourceException;
   26.53 +import java.util.ResourceBundle;
   26.54 +import java.util.TimeZone;
   26.55 +import java.util.spi.LocaleServiceProvider;
   26.56 +import sun.util.LocaleServiceProviderPool;
   26.57 +
   26.58 +/**
   26.59 + * {@code DateFormat} is an abstract class for date/time formatting subclasses which
   26.60 + * formats and parses dates or time in a language-independent manner.
   26.61 + * The date/time formatting subclass, such as {@link SimpleDateFormat}, allows for
   26.62 + * formatting (i.e., date -> text), parsing (text -> date), and
   26.63 + * normalization.  The date is represented as a <code>Date</code> object or
   26.64 + * as the milliseconds since January 1, 1970, 00:00:00 GMT.
   26.65 + *
   26.66 + * <p>{@code DateFormat} provides many class methods for obtaining default date/time
   26.67 + * formatters based on the default or a given locale and a number of formatting
   26.68 + * styles. The formatting styles include {@link #FULL}, {@link #LONG}, {@link #MEDIUM}, and {@link #SHORT}. More
   26.69 + * detail and examples of using these styles are provided in the method
   26.70 + * descriptions.
   26.71 + *
   26.72 + * <p>{@code DateFormat} helps you to format and parse dates for any locale.
   26.73 + * Your code can be completely independent of the locale conventions for
   26.74 + * months, days of the week, or even the calendar format: lunar vs. solar.
   26.75 + *
   26.76 + * <p>To format a date for the current Locale, use one of the
   26.77 + * static factory methods:
   26.78 + * <pre>
   26.79 + *  myString = DateFormat.getDateInstance().format(myDate);
   26.80 + * </pre>
   26.81 + * <p>If you are formatting multiple dates, it is
   26.82 + * more efficient to get the format and use it multiple times so that
   26.83 + * the system doesn't have to fetch the information about the local
   26.84 + * language and country conventions multiple times.
   26.85 + * <pre>
   26.86 + *  DateFormat df = DateFormat.getDateInstance();
   26.87 + *  for (int i = 0; i < myDate.length; ++i) {
   26.88 + *    output.println(df.format(myDate[i]) + "; ");
   26.89 + *  }
   26.90 + * </pre>
   26.91 + * <p>To format a date for a different Locale, specify it in the
   26.92 + * call to {@link #getDateInstance(int, Locale) getDateInstance()}.
   26.93 + * <pre>
   26.94 + *  DateFormat df = DateFormat.getDateInstance(DateFormat.LONG, Locale.FRANCE);
   26.95 + * </pre>
   26.96 + * <p>You can use a DateFormat to parse also.
   26.97 + * <pre>
   26.98 + *  myDate = df.parse(myString);
   26.99 + * </pre>
  26.100 + * <p>Use {@code getDateInstance} to get the normal date format for that country.
  26.101 + * There are other static factory methods available.
  26.102 + * Use {@code getTimeInstance} to get the time format for that country.
  26.103 + * Use {@code getDateTimeInstance} to get a date and time format. You can pass in
  26.104 + * different options to these factory methods to control the length of the
  26.105 + * result; from {@link #SHORT} to {@link #MEDIUM} to {@link #LONG} to {@link #FULL}. The exact result depends
  26.106 + * on the locale, but generally:
  26.107 + * <ul><li>{@link #SHORT} is completely numeric, such as {@code 12.13.52} or {@code 3:30pm}
  26.108 + * <li>{@link #MEDIUM} is longer, such as {@code Jan 12, 1952}
  26.109 + * <li>{@link #LONG} is longer, such as {@code January 12, 1952} or {@code 3:30:32pm}
  26.110 + * <li>{@link #FULL} is pretty completely specified, such as
  26.111 + * {@code Tuesday, April 12, 1952 AD or 3:30:42pm PST}.
  26.112 + * </ul>
  26.113 + *
  26.114 + * <p>You can also set the time zone on the format if you wish.
  26.115 + * If you want even more control over the format or parsing,
  26.116 + * (or want to give your users more control),
  26.117 + * you can try casting the {@code DateFormat} you get from the factory methods
  26.118 + * to a {@link SimpleDateFormat}. This will work for the majority
  26.119 + * of countries; just remember to put it in a {@code try} block in case you
  26.120 + * encounter an unusual one.
  26.121 + *
  26.122 + * <p>You can also use forms of the parse and format methods with
  26.123 + * {@link ParsePosition} and {@link FieldPosition} to
  26.124 + * allow you to
  26.125 + * <ul><li>progressively parse through pieces of a string.
  26.126 + * <li>align any particular field, or find out where it is for selection
  26.127 + * on the screen.
  26.128 + * </ul>
  26.129 + *
  26.130 + * <h4><a name="synchronization">Synchronization</a></h4>
  26.131 + *
  26.132 + * <p>
  26.133 + * Date formats are not synchronized.
  26.134 + * It is recommended to create separate format instances for each thread.
  26.135 + * If multiple threads access a format concurrently, it must be synchronized
  26.136 + * externally.
  26.137 + *
  26.138 + * @see          Format
  26.139 + * @see          NumberFormat
  26.140 + * @see          SimpleDateFormat
  26.141 + * @see          java.util.Calendar
  26.142 + * @see          java.util.GregorianCalendar
  26.143 + * @see          java.util.TimeZone
  26.144 + * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
  26.145 + */
  26.146 +public abstract class DateFormat extends Format {
  26.147 +
  26.148 +    /**
  26.149 +     * The {@link Calendar} instance used for calculating the date-time fields
  26.150 +     * and the instant of time. This field is used for both formatting and
  26.151 +     * parsing.
  26.152 +     *
  26.153 +     * <p>Subclasses should initialize this field to a {@link Calendar}
  26.154 +     * appropriate for the {@link Locale} associated with this
  26.155 +     * <code>DateFormat</code>.
  26.156 +     * @serial
  26.157 +     */
  26.158 +    protected Calendar calendar;
  26.159 +
  26.160 +    /**
  26.161 +     * The number formatter that <code>DateFormat</code> uses to format numbers
  26.162 +     * in dates and times.  Subclasses should initialize this to a number format
  26.163 +     * appropriate for the locale associated with this <code>DateFormat</code>.
  26.164 +     * @serial
  26.165 +     */
  26.166 +    protected NumberFormat numberFormat;
  26.167 +
  26.168 +    /**
  26.169 +     * Useful constant for ERA field alignment.
  26.170 +     * Used in FieldPosition of date/time formatting.
  26.171 +     */
  26.172 +    public final static int ERA_FIELD = 0;
  26.173 +    /**
  26.174 +     * Useful constant for YEAR field alignment.
  26.175 +     * Used in FieldPosition of date/time formatting.
  26.176 +     */
  26.177 +    public final static int YEAR_FIELD = 1;
  26.178 +    /**
  26.179 +     * Useful constant for MONTH field alignment.
  26.180 +     * Used in FieldPosition of date/time formatting.
  26.181 +     */
  26.182 +    public final static int MONTH_FIELD = 2;
  26.183 +    /**
  26.184 +     * Useful constant for DATE field alignment.
  26.185 +     * Used in FieldPosition of date/time formatting.
  26.186 +     */
  26.187 +    public final static int DATE_FIELD = 3;
  26.188 +    /**
  26.189 +     * Useful constant for one-based HOUR_OF_DAY field alignment.
  26.190 +     * Used in FieldPosition of date/time formatting.
  26.191 +     * HOUR_OF_DAY1_FIELD is used for the one-based 24-hour clock.
  26.192 +     * For example, 23:59 + 01:00 results in 24:59.
  26.193 +     */
  26.194 +    public final static int HOUR_OF_DAY1_FIELD = 4;
  26.195 +    /**
  26.196 +     * Useful constant for zero-based HOUR_OF_DAY field alignment.
  26.197 +     * Used in FieldPosition of date/time formatting.
  26.198 +     * HOUR_OF_DAY0_FIELD is used for the zero-based 24-hour clock.
  26.199 +     * For example, 23:59 + 01:00 results in 00:59.
  26.200 +     */
  26.201 +    public final static int HOUR_OF_DAY0_FIELD = 5;
  26.202 +    /**
  26.203 +     * Useful constant for MINUTE field alignment.
  26.204 +     * Used in FieldPosition of date/time formatting.
  26.205 +     */
  26.206 +    public final static int MINUTE_FIELD = 6;
  26.207 +    /**
  26.208 +     * Useful constant for SECOND field alignment.
  26.209 +     * Used in FieldPosition of date/time formatting.
  26.210 +     */
  26.211 +    public final static int SECOND_FIELD = 7;
  26.212 +    /**
  26.213 +     * Useful constant for MILLISECOND field alignment.
  26.214 +     * Used in FieldPosition of date/time formatting.
  26.215 +     */
  26.216 +    public final static int MILLISECOND_FIELD = 8;
  26.217 +    /**
  26.218 +     * Useful constant for DAY_OF_WEEK field alignment.
  26.219 +     * Used in FieldPosition of date/time formatting.
  26.220 +     */
  26.221 +    public final static int DAY_OF_WEEK_FIELD = 9;
  26.222 +    /**
  26.223 +     * Useful constant for DAY_OF_YEAR field alignment.
  26.224 +     * Used in FieldPosition of date/time formatting.
  26.225 +     */
  26.226 +    public final static int DAY_OF_YEAR_FIELD = 10;
  26.227 +    /**
  26.228 +     * Useful constant for DAY_OF_WEEK_IN_MONTH field alignment.
  26.229 +     * Used in FieldPosition of date/time formatting.
  26.230 +     */
  26.231 +    public final static int DAY_OF_WEEK_IN_MONTH_FIELD = 11;
  26.232 +    /**
  26.233 +     * Useful constant for WEEK_OF_YEAR field alignment.
  26.234 +     * Used in FieldPosition of date/time formatting.
  26.235 +     */
  26.236 +    public final static int WEEK_OF_YEAR_FIELD = 12;
  26.237 +    /**
  26.238 +     * Useful constant for WEEK_OF_MONTH field alignment.
  26.239 +     * Used in FieldPosition of date/time formatting.
  26.240 +     */
  26.241 +    public final static int WEEK_OF_MONTH_FIELD = 13;
  26.242 +    /**
  26.243 +     * Useful constant for AM_PM field alignment.
  26.244 +     * Used in FieldPosition of date/time formatting.
  26.245 +     */
  26.246 +    public final static int AM_PM_FIELD = 14;
  26.247 +    /**
  26.248 +     * Useful constant for one-based HOUR field alignment.
  26.249 +     * Used in FieldPosition of date/time formatting.
  26.250 +     * HOUR1_FIELD is used for the one-based 12-hour clock.
  26.251 +     * For example, 11:30 PM + 1 hour results in 12:30 AM.
  26.252 +     */
  26.253 +    public final static int HOUR1_FIELD = 15;
  26.254 +    /**
  26.255 +     * Useful constant for zero-based HOUR field alignment.
  26.256 +     * Used in FieldPosition of date/time formatting.
  26.257 +     * HOUR0_FIELD is used for the zero-based 12-hour clock.
  26.258 +     * For example, 11:30 PM + 1 hour results in 00:30 AM.
  26.259 +     */
  26.260 +    public final static int HOUR0_FIELD = 16;
  26.261 +    /**
  26.262 +     * Useful constant for TIMEZONE field alignment.
  26.263 +     * Used in FieldPosition of date/time formatting.
  26.264 +     */
  26.265 +    public final static int TIMEZONE_FIELD = 17;
  26.266 +
  26.267 +    // Proclaim serial compatibility with 1.1 FCS
  26.268 +    private static final long serialVersionUID = 7218322306649953788L;
  26.269 +
  26.270 +    /**
  26.271 +     * Overrides Format.
  26.272 +     * Formats a time object into a time string. Examples of time objects
  26.273 +     * are a time value expressed in milliseconds and a Date object.
  26.274 +     * @param obj must be a Number or a Date.
  26.275 +     * @param toAppendTo the string buffer for the returning time string.
  26.276 +     * @return the string buffer passed in as toAppendTo, with formatted text appended.
  26.277 +     * @param fieldPosition keeps track of the position of the field
  26.278 +     * within the returned string.
  26.279 +     * On input: an alignment field,
  26.280 +     * if desired. On output: the offsets of the alignment field. For
  26.281 +     * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  26.282 +     * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  26.283 +     * begin index and end index of fieldPosition will be set to
  26.284 +     * 0 and 4, respectively.
  26.285 +     * Notice that if the same time field appears
  26.286 +     * more than once in a pattern, the fieldPosition will be set for the first
  26.287 +     * occurrence of that time field. For instance, formatting a Date to
  26.288 +     * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  26.289 +     * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  26.290 +     * the begin index and end index of fieldPosition will be set to
  26.291 +     * 5 and 8, respectively, for the first occurrence of the timezone
  26.292 +     * pattern character 'z'.
  26.293 +     * @see java.text.Format
  26.294 +     */
  26.295 +    public final StringBuffer format(Object obj, StringBuffer toAppendTo,
  26.296 +                                     FieldPosition fieldPosition)
  26.297 +    {
  26.298 +        if (obj instanceof Date)
  26.299 +            return format( (Date)obj, toAppendTo, fieldPosition );
  26.300 +        else if (obj instanceof Number)
  26.301 +            return format( new Date(((Number)obj).longValue()),
  26.302 +                          toAppendTo, fieldPosition );
  26.303 +        else
  26.304 +            throw new IllegalArgumentException("Cannot format given Object as a Date");
  26.305 +    }
  26.306 +
  26.307 +    /**
  26.308 +     * Formats a Date into a date/time string.
  26.309 +     * @param date a Date to be formatted into a date/time string.
  26.310 +     * @param toAppendTo the string buffer for the returning date/time string.
  26.311 +     * @param fieldPosition keeps track of the position of the field
  26.312 +     * within the returned string.
  26.313 +     * On input: an alignment field,
  26.314 +     * if desired. On output: the offsets of the alignment field. For
  26.315 +     * example, given a time text "1996.07.10 AD at 15:08:56 PDT",
  26.316 +     * if the given fieldPosition is DateFormat.YEAR_FIELD, the
  26.317 +     * begin index and end index of fieldPosition will be set to
  26.318 +     * 0 and 4, respectively.
  26.319 +     * Notice that if the same time field appears
  26.320 +     * more than once in a pattern, the fieldPosition will be set for the first
  26.321 +     * occurrence of that time field. For instance, formatting a Date to
  26.322 +     * the time string "1 PM PDT (Pacific Daylight Time)" using the pattern
  26.323 +     * "h a z (zzzz)" and the alignment field DateFormat.TIMEZONE_FIELD,
  26.324 +     * the begin index and end index of fieldPosition will be set to
  26.325 +     * 5 and 8, respectively, for the first occurrence of the timezone
  26.326 +     * pattern character 'z'.
  26.327 +     * @return the string buffer passed in as toAppendTo, with formatted text appended.
  26.328 +     */
  26.329 +    public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
  26.330 +                                        FieldPosition fieldPosition);
  26.331 +
  26.332 +    /**
  26.333 +     * Formats a Date into a date/time string.
  26.334 +     * @param date the time value to be formatted into a time string.
  26.335 +     * @return the formatted time string.
  26.336 +     */
  26.337 +    public final String format(Date date)
  26.338 +    {
  26.339 +        return format(date, new StringBuffer(),
  26.340 +                      DontCareFieldPosition.INSTANCE).toString();
  26.341 +    }
  26.342 +
  26.343 +    /**
  26.344 +     * Parses text from the beginning of the given string to produce a date.
  26.345 +     * The method may not use the entire text of the given string.
  26.346 +     * <p>
  26.347 +     * See the {@link #parse(String, ParsePosition)} method for more information
  26.348 +     * on date parsing.
  26.349 +     *
  26.350 +     * @param source A <code>String</code> whose beginning should be parsed.
  26.351 +     * @return A <code>Date</code> parsed from the string.
  26.352 +     * @exception ParseException if the beginning of the specified string
  26.353 +     *            cannot be parsed.
  26.354 +     */
  26.355 +    public Date parse(String source) throws ParseException
  26.356 +    {
  26.357 +        ParsePosition pos = new ParsePosition(0);
  26.358 +        Date result = parse(source, pos);
  26.359 +        if (pos.index == 0)
  26.360 +            throw new ParseException("Unparseable date: \"" + source + "\"" ,
  26.361 +                pos.errorIndex);
  26.362 +        return result;
  26.363 +    }
  26.364 +
  26.365 +    /**
  26.366 +     * Parse a date/time string according to the given parse position.  For
  26.367 +     * example, a time text {@code "07/10/96 4:5 PM, PDT"} will be parsed into a {@code Date}
  26.368 +     * that is equivalent to {@code Date(837039900000L)}.
  26.369 +     *
  26.370 +     * <p> By default, parsing is lenient: If the input is not in the form used
  26.371 +     * by this object's format method but can still be parsed as a date, then
  26.372 +     * the parse succeeds.  Clients may insist on strict adherence to the
  26.373 +     * format by calling {@link #setLenient(boolean) setLenient(false)}.
  26.374 +     *
  26.375 +     * <p>This parsing operation uses the {@link #calendar} to produce
  26.376 +     * a {@code Date}. As a result, the {@code calendar}'s date-time
  26.377 +     * fields and the {@code TimeZone} value may have been
  26.378 +     * overwritten, depending on subclass implementations. Any {@code
  26.379 +     * TimeZone} value that has previously been set by a call to
  26.380 +     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
  26.381 +     * to be restored for further operations.
  26.382 +     *
  26.383 +     * @param source  The date/time string to be parsed
  26.384 +     *
  26.385 +     * @param pos   On input, the position at which to start parsing; on
  26.386 +     *              output, the position at which parsing terminated, or the
  26.387 +     *              start position if the parse failed.
  26.388 +     *
  26.389 +     * @return      A {@code Date}, or {@code null} if the input could not be parsed
  26.390 +     */
  26.391 +    public abstract Date parse(String source, ParsePosition pos);
  26.392 +
  26.393 +    /**
  26.394 +     * Parses text from a string to produce a <code>Date</code>.
  26.395 +     * <p>
  26.396 +     * The method attempts to parse text starting at the index given by
  26.397 +     * <code>pos</code>.
  26.398 +     * If parsing succeeds, then the index of <code>pos</code> is updated
  26.399 +     * to the index after the last character used (parsing does not necessarily
  26.400 +     * use all characters up to the end of the string), and the parsed
  26.401 +     * date is returned. The updated <code>pos</code> can be used to
  26.402 +     * indicate the starting point for the next call to this method.
  26.403 +     * If an error occurs, then the index of <code>pos</code> is not
  26.404 +     * changed, the error index of <code>pos</code> is set to the index of
  26.405 +     * the character where the error occurred, and null is returned.
  26.406 +     * <p>
  26.407 +     * See the {@link #parse(String, ParsePosition)} method for more information
  26.408 +     * on date parsing.
  26.409 +     *
  26.410 +     * @param source A <code>String</code>, part of which should be parsed.
  26.411 +     * @param pos A <code>ParsePosition</code> object with index and error
  26.412 +     *            index information as described above.
  26.413 +     * @return A <code>Date</code> parsed from the string. In case of
  26.414 +     *         error, returns null.
  26.415 +     * @exception NullPointerException if <code>pos</code> is null.
  26.416 +     */
  26.417 +    public Object parseObject(String source, ParsePosition pos) {
  26.418 +        return parse(source, pos);
  26.419 +    }
  26.420 +
  26.421 +    /**
  26.422 +     * Constant for full style pattern.
  26.423 +     */
  26.424 +    public static final int FULL = 0;
  26.425 +    /**
  26.426 +     * Constant for long style pattern.
  26.427 +     */
  26.428 +    public static final int LONG = 1;
  26.429 +    /**
  26.430 +     * Constant for medium style pattern.
  26.431 +     */
  26.432 +    public static final int MEDIUM = 2;
  26.433 +    /**
  26.434 +     * Constant for short style pattern.
  26.435 +     */
  26.436 +    public static final int SHORT = 3;
  26.437 +    /**
  26.438 +     * Constant for default style pattern.  Its value is MEDIUM.
  26.439 +     */
  26.440 +    public static final int DEFAULT = MEDIUM;
  26.441 +
  26.442 +    /**
  26.443 +     * Gets the time formatter with the default formatting style
  26.444 +     * for the default locale.
  26.445 +     * @return a time formatter.
  26.446 +     */
  26.447 +    public final static DateFormat getTimeInstance()
  26.448 +    {
  26.449 +        return get(DEFAULT, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
  26.450 +    }
  26.451 +
  26.452 +    /**
  26.453 +     * Gets the time formatter with the given formatting style
  26.454 +     * for the default locale.
  26.455 +     * @param style the given formatting style. For example,
  26.456 +     * SHORT for "h:mm a" in the US locale.
  26.457 +     * @return a time formatter.
  26.458 +     */
  26.459 +    public final static DateFormat getTimeInstance(int style)
  26.460 +    {
  26.461 +        return get(style, 0, 1, Locale.getDefault(Locale.Category.FORMAT));
  26.462 +    }
  26.463 +
  26.464 +    /**
  26.465 +     * Gets the time formatter with the given formatting style
  26.466 +     * for the given locale.
  26.467 +     * @param style the given formatting style. For example,
  26.468 +     * SHORT for "h:mm a" in the US locale.
  26.469 +     * @param aLocale the given locale.
  26.470 +     * @return a time formatter.
  26.471 +     */
  26.472 +    public final static DateFormat getTimeInstance(int style,
  26.473 +                                                 Locale aLocale)
  26.474 +    {
  26.475 +        return get(style, 0, 1, aLocale);
  26.476 +    }
  26.477 +
  26.478 +    /**
  26.479 +     * Gets the date formatter with the default formatting style
  26.480 +     * for the default locale.
  26.481 +     * @return a date formatter.
  26.482 +     */
  26.483 +    public final static DateFormat getDateInstance()
  26.484 +    {
  26.485 +        return get(0, DEFAULT, 2, Locale.getDefault(Locale.Category.FORMAT));
  26.486 +    }
  26.487 +
  26.488 +    /**
  26.489 +     * Gets the date formatter with the given formatting style
  26.490 +     * for the default locale.
  26.491 +     * @param style the given formatting style. For example,
  26.492 +     * SHORT for "M/d/yy" in the US locale.
  26.493 +     * @return a date formatter.
  26.494 +     */
  26.495 +    public final static DateFormat getDateInstance(int style)
  26.496 +    {
  26.497 +        return get(0, style, 2, Locale.getDefault(Locale.Category.FORMAT));
  26.498 +    }
  26.499 +
  26.500 +    /**
  26.501 +     * Gets the date formatter with the given formatting style
  26.502 +     * for the given locale.
  26.503 +     * @param style the given formatting style. For example,
  26.504 +     * SHORT for "M/d/yy" in the US locale.
  26.505 +     * @param aLocale the given locale.
  26.506 +     * @return a date formatter.
  26.507 +     */
  26.508 +    public final static DateFormat getDateInstance(int style,
  26.509 +                                                 Locale aLocale)
  26.510 +    {
  26.511 +        return get(0, style, 2, aLocale);
  26.512 +    }
  26.513 +
  26.514 +    /**
  26.515 +     * Gets the date/time formatter with the default formatting style
  26.516 +     * for the default locale.
  26.517 +     * @return a date/time formatter.
  26.518 +     */
  26.519 +    public final static DateFormat getDateTimeInstance()
  26.520 +    {
  26.521 +        return get(DEFAULT, DEFAULT, 3, Locale.getDefault(Locale.Category.FORMAT));
  26.522 +    }
  26.523 +
  26.524 +    /**
  26.525 +     * Gets the date/time formatter with the given date and time
  26.526 +     * formatting styles for the default locale.
  26.527 +     * @param dateStyle the given date formatting style. For example,
  26.528 +     * SHORT for "M/d/yy" in the US locale.
  26.529 +     * @param timeStyle the given time formatting style. For example,
  26.530 +     * SHORT for "h:mm a" in the US locale.
  26.531 +     * @return a date/time formatter.
  26.532 +     */
  26.533 +    public final static DateFormat getDateTimeInstance(int dateStyle,
  26.534 +                                                       int timeStyle)
  26.535 +    {
  26.536 +        return get(timeStyle, dateStyle, 3, Locale.getDefault(Locale.Category.FORMAT));
  26.537 +    }
  26.538 +
  26.539 +    /**
  26.540 +     * Gets the date/time formatter with the given formatting styles
  26.541 +     * for the given locale.
  26.542 +     * @param dateStyle the given date formatting style.
  26.543 +     * @param timeStyle the given time formatting style.
  26.544 +     * @param aLocale the given locale.
  26.545 +     * @return a date/time formatter.
  26.546 +     */
  26.547 +    public final static DateFormat
  26.548 +        getDateTimeInstance(int dateStyle, int timeStyle, Locale aLocale)
  26.549 +    {
  26.550 +        return get(timeStyle, dateStyle, 3, aLocale);
  26.551 +    }
  26.552 +
  26.553 +    /**
  26.554 +     * Get a default date/time formatter that uses the SHORT style for both the
  26.555 +     * date and the time.
  26.556 +     */
  26.557 +    public final static DateFormat getInstance() {
  26.558 +        return getDateTimeInstance(SHORT, SHORT);
  26.559 +    }
  26.560 +
  26.561 +    /**
  26.562 +     * Returns an array of all locales for which the
  26.563 +     * <code>get*Instance</code> methods of this class can return
  26.564 +     * localized instances.
  26.565 +     * The returned array represents the union of locales supported by the Java
  26.566 +     * runtime and by installed
  26.567 +     * {@link java.text.spi.DateFormatProvider DateFormatProvider} implementations.
  26.568 +     * It must contain at least a <code>Locale</code> instance equal to
  26.569 +     * {@link java.util.Locale#US Locale.US}.
  26.570 +     *
  26.571 +     * @return An array of locales for which localized
  26.572 +     *         <code>DateFormat</code> instances are available.
  26.573 +     */
  26.574 +    public static Locale[] getAvailableLocales()
  26.575 +    {
  26.576 +        LocaleServiceProviderPool pool =
  26.577 +            LocaleServiceProviderPool.getPool(DateFormatProvider.class);
  26.578 +        return pool.getAvailableLocales();
  26.579 +    }
  26.580 +
  26.581 +    /**
  26.582 +     * Set the calendar to be used by this date format.  Initially, the default
  26.583 +     * calendar for the specified or default locale is used.
  26.584 +     *
  26.585 +     * <p>Any {@link java.util.TimeZone TimeZone} and {@linkplain
  26.586 +     * #isLenient() leniency} values that have previously been set are
  26.587 +     * overwritten by {@code newCalendar}'s values.
  26.588 +     *
  26.589 +     * @param newCalendar the new {@code Calendar} to be used by the date format
  26.590 +     */
  26.591 +    public void setCalendar(Calendar newCalendar)
  26.592 +    {
  26.593 +        this.calendar = newCalendar;
  26.594 +    }
  26.595 +
  26.596 +    /**
  26.597 +     * Gets the calendar associated with this date/time formatter.
  26.598 +     *
  26.599 +     * @return the calendar associated with this date/time formatter.
  26.600 +     */
  26.601 +    public Calendar getCalendar()
  26.602 +    {
  26.603 +        return calendar;
  26.604 +    }
  26.605 +
  26.606 +    /**
  26.607 +     * Allows you to set the number formatter.
  26.608 +     * @param newNumberFormat the given new NumberFormat.
  26.609 +     */
  26.610 +    public void setNumberFormat(NumberFormat newNumberFormat)
  26.611 +    {
  26.612 +        this.numberFormat = newNumberFormat;
  26.613 +    }
  26.614 +
  26.615 +    /**
  26.616 +     * Gets the number formatter which this date/time formatter uses to
  26.617 +     * format and parse a time.
  26.618 +     * @return the number formatter which this date/time formatter uses.
  26.619 +     */
  26.620 +    public NumberFormat getNumberFormat()
  26.621 +    {
  26.622 +        return numberFormat;
  26.623 +    }
  26.624 +
  26.625 +    /**
  26.626 +     * Sets the time zone for the calendar of this {@code DateFormat} object.
  26.627 +     * This method is equivalent to the following call.
  26.628 +     * <blockquote><pre>
  26.629 +     *  getCalendar().setTimeZone(zone)
  26.630 +     * </pre></blockquote>
  26.631 +     *
  26.632 +     * <p>The {@code TimeZone} set by this method is overwritten by a
  26.633 +     * {@link #setCalendar(java.util.Calendar) setCalendar} call.
  26.634 +     *
  26.635 +     * <p>The {@code TimeZone} set by this method may be overwritten as
  26.636 +     * a result of a call to the parse method.
  26.637 +     *
  26.638 +     * @param zone the given new time zone.
  26.639 +     */
  26.640 +    public void setTimeZone(TimeZone zone)
  26.641 +    {
  26.642 +        calendar.setTimeZone(zone);
  26.643 +    }
  26.644 +
  26.645 +    /**
  26.646 +     * Gets the time zone.
  26.647 +     * This method is equivalent to the following call.
  26.648 +     * <blockquote><pre>
  26.649 +     *  getCalendar().getTimeZone()
  26.650 +     * </pre></blockquote>
  26.651 +     *
  26.652 +     * @return the time zone associated with the calendar of DateFormat.
  26.653 +     */
  26.654 +    public TimeZone getTimeZone()
  26.655 +    {
  26.656 +        return calendar.getTimeZone();
  26.657 +    }
  26.658 +
  26.659 +    /**
  26.660 +     * Specify whether or not date/time parsing is to be lenient.  With
  26.661 +     * lenient parsing, the parser may use heuristics to interpret inputs that
  26.662 +     * do not precisely match this object's format.  With strict parsing,
  26.663 +     * inputs must match this object's format.
  26.664 +     *
  26.665 +     * <p>This method is equivalent to the following call.
  26.666 +     * <blockquote><pre>
  26.667 +     *  getCalendar().setLenient(lenient)
  26.668 +     * </pre></blockquote>
  26.669 +     *
  26.670 +     * <p>This leniency value is overwritten by a call to {@link
  26.671 +     * #setCalendar(java.util.Calendar) setCalendar()}.
  26.672 +     *
  26.673 +     * @param lenient when {@code true}, parsing is lenient
  26.674 +     * @see java.util.Calendar#setLenient(boolean)
  26.675 +     */
  26.676 +    public void setLenient(boolean lenient)
  26.677 +    {
  26.678 +        calendar.setLenient(lenient);
  26.679 +    }
  26.680 +
  26.681 +    /**
  26.682 +     * Tell whether date/time parsing is to be lenient.
  26.683 +     * This method is equivalent to the following call.
  26.684 +     * <blockquote><pre>
  26.685 +     *  getCalendar().isLenient()
  26.686 +     * </pre></blockquote>
  26.687 +     *
  26.688 +     * @return {@code true} if the {@link #calendar} is lenient;
  26.689 +     *         {@code false} otherwise.
  26.690 +     * @see java.util.Calendar#isLenient()
  26.691 +     */
  26.692 +    public boolean isLenient()
  26.693 +    {
  26.694 +        return calendar.isLenient();
  26.695 +    }
  26.696 +
  26.697 +    /**
  26.698 +     * Overrides hashCode
  26.699 +     */
  26.700 +    public int hashCode() {
  26.701 +        return numberFormat.hashCode();
  26.702 +        // just enough fields for a reasonable distribution
  26.703 +    }
  26.704 +
  26.705 +    /**
  26.706 +     * Overrides equals
  26.707 +     */
  26.708 +    public boolean equals(Object obj) {
  26.709 +        if (this == obj) return true;
  26.710 +        if (obj == null || getClass() != obj.getClass()) return false;
  26.711 +        DateFormat other = (DateFormat) obj;
  26.712 +        return (// calendar.equivalentTo(other.calendar) // THIS API DOESN'T EXIST YET!
  26.713 +                calendar.getFirstDayOfWeek() == other.calendar.getFirstDayOfWeek() &&
  26.714 +                calendar.getMinimalDaysInFirstWeek() == other.calendar.getMinimalDaysInFirstWeek() &&
  26.715 +                calendar.isLenient() == other.calendar.isLenient() &&
  26.716 +                calendar.getTimeZone().equals(other.calendar.getTimeZone()) &&
  26.717 +                numberFormat.equals(other.numberFormat));
  26.718 +    }
  26.719 +
  26.720 +    /**
  26.721 +     * Overrides Cloneable
  26.722 +     */
  26.723 +    public Object clone()
  26.724 +    {
  26.725 +        DateFormat other = (DateFormat) super.clone();
  26.726 +        other.calendar = (Calendar) calendar.clone();
  26.727 +        other.numberFormat = (NumberFormat) numberFormat.clone();
  26.728 +        return other;
  26.729 +    }
  26.730 +
  26.731 +    /**
  26.732 +     * Creates a DateFormat with the given time and/or date style in the given
  26.733 +     * locale.
  26.734 +     * @param timeStyle a value from 0 to 3 indicating the time format,
  26.735 +     * ignored if flags is 2
  26.736 +     * @param dateStyle a value from 0 to 3 indicating the time format,
  26.737 +     * ignored if flags is 1
  26.738 +     * @param flags either 1 for a time format, 2 for a date format,
  26.739 +     * or 3 for a date/time format
  26.740 +     * @param loc the locale for the format
  26.741 +     */
  26.742 +    private static DateFormat get(int timeStyle, int dateStyle,
  26.743 +                                  int flags, Locale loc) {
  26.744 +        if ((flags & 1) != 0) {
  26.745 +            if (timeStyle < 0 || timeStyle > 3) {
  26.746 +                throw new IllegalArgumentException("Illegal time style " + timeStyle);
  26.747 +            }
  26.748 +        } else {
  26.749 +            timeStyle = -1;
  26.750 +        }
  26.751 +        if ((flags & 2) != 0) {
  26.752 +            if (dateStyle < 0 || dateStyle > 3) {
  26.753 +                throw new IllegalArgumentException("Illegal date style " + dateStyle);
  26.754 +            }
  26.755 +        } else {
  26.756 +            dateStyle = -1;
  26.757 +        }
  26.758 +        try {
  26.759 +            // Check whether a provider can provide an implementation that's closer
  26.760 +            // to the requested locale than what the Java runtime itself can provide.
  26.761 +            LocaleServiceProviderPool pool =
  26.762 +                LocaleServiceProviderPool.getPool(DateFormatProvider.class);
  26.763 +            if (pool.hasProviders()) {
  26.764 +                DateFormat providersInstance = pool.getLocalizedObject(
  26.765 +                                                    DateFormatGetter.INSTANCE,
  26.766 +                                                    loc,
  26.767 +                                                    timeStyle,
  26.768 +                                                    dateStyle,
  26.769 +                                                    flags);
  26.770 +                if (providersInstance != null) {
  26.771 +                    return providersInstance;
  26.772 +                }
  26.773 +            }
  26.774 +
  26.775 +            return new SimpleDateFormat(timeStyle, dateStyle, loc);
  26.776 +        } catch (MissingResourceException e) {
  26.777 +            return new SimpleDateFormat("M/d/yy h:mm a");
  26.778 +        }
  26.779 +    }
  26.780 +
  26.781 +    /**
  26.782 +     * Create a new date format.
  26.783 +     */
  26.784 +    protected DateFormat() {}
  26.785 +
  26.786 +    /**
  26.787 +     * Defines constants that are used as attribute keys in the
  26.788 +     * <code>AttributedCharacterIterator</code> returned
  26.789 +     * from <code>DateFormat.formatToCharacterIterator</code> and as
  26.790 +     * field identifiers in <code>FieldPosition</code>.
  26.791 +     * <p>
  26.792 +     * The class also provides two methods to map
  26.793 +     * between its constants and the corresponding Calendar constants.
  26.794 +     *
  26.795 +     * @since 1.4
  26.796 +     * @see java.util.Calendar
  26.797 +     */
  26.798 +    public static class Field extends Format.Field {
  26.799 +
  26.800 +        // Proclaim serial compatibility with 1.4 FCS
  26.801 +        private static final long serialVersionUID = 7441350119349544720L;
  26.802 +
  26.803 +        // table of all instances in this class, used by readResolve
  26.804 +        private static final Map instanceMap = new HashMap(18);
  26.805 +        // Maps from Calendar constant (such as Calendar.ERA) to Field
  26.806 +        // constant (such as Field.ERA).
  26.807 +        private static final Field[] calendarToFieldMapping =
  26.808 +                                             new Field[Calendar.FIELD_COUNT];
  26.809 +
  26.810 +        /** Calendar field. */
  26.811 +        private int calendarField;
  26.812 +
  26.813 +        /**
  26.814 +         * Returns the <code>Field</code> constant that corresponds to
  26.815 +         * the <code>Calendar</code> constant <code>calendarField</code>.
  26.816 +         * If there is no direct mapping between the <code>Calendar</code>
  26.817 +         * constant and a <code>Field</code>, null is returned.
  26.818 +         *
  26.819 +         * @throws IllegalArgumentException if <code>calendarField</code> is
  26.820 +         *         not the value of a <code>Calendar</code> field constant.
  26.821 +         * @param calendarField Calendar field constant
  26.822 +         * @return Field instance representing calendarField.
  26.823 +         * @see java.util.Calendar
  26.824 +         */
  26.825 +        public static Field ofCalendarField(int calendarField) {
  26.826 +            if (calendarField < 0 || calendarField >=
  26.827 +                        calendarToFieldMapping.length) {
  26.828 +                throw new IllegalArgumentException("Unknown Calendar constant "
  26.829 +                                                   + calendarField);
  26.830 +            }
  26.831 +            return calendarToFieldMapping[calendarField];
  26.832 +        }
  26.833 +
  26.834 +        /**
  26.835 +         * Creates a <code>Field</code>.
  26.836 +         *
  26.837 +         * @param name the name of the <code>Field</code>
  26.838 +         * @param calendarField the <code>Calendar</code> constant this
  26.839 +         *        <code>Field</code> corresponds to; any value, even one
  26.840 +         *        outside the range of legal <code>Calendar</code> values may
  26.841 +         *        be used, but <code>-1</code> should be used for values
  26.842 +         *        that don't correspond to legal <code>Calendar</code> values
  26.843 +         */
  26.844 +        protected Field(String name, int calendarField) {
  26.845 +            super(name);
  26.846 +            this.calendarField = calendarField;
  26.847 +            if (this.getClass() == DateFormat.Field.class) {
  26.848 +                instanceMap.put(name, this);
  26.849 +                if (calendarField >= 0) {
  26.850 +                    // assert(calendarField < Calendar.FIELD_COUNT);
  26.851 +                    calendarToFieldMapping[calendarField] = this;
  26.852 +                }
  26.853 +            }
  26.854 +        }
  26.855 +
  26.856 +        /**
  26.857 +         * Returns the <code>Calendar</code> field associated with this
  26.858 +         * attribute. For example, if this represents the hours field of
  26.859 +         * a <code>Calendar</code>, this would return
  26.860 +         * <code>Calendar.HOUR</code>. If there is no corresponding
  26.861 +         * <code>Calendar</code> constant, this will return -1.
  26.862 +         *
  26.863 +         * @return Calendar constant for this field
  26.864 +         * @see java.util.Calendar
  26.865 +         */
  26.866 +        public int getCalendarField() {
  26.867 +            return calendarField;
  26.868 +        }
  26.869 +
  26.870 +        /**
  26.871 +         * Resolves instances being deserialized to the predefined constants.
  26.872 +         *
  26.873 +         * @throws InvalidObjectException if the constant could not be
  26.874 +         *         resolved.
  26.875 +         * @return resolved DateFormat.Field constant
  26.876 +         */
  26.877 +        protected Object readResolve() throws InvalidObjectException {
  26.878 +            if (this.getClass() != DateFormat.Field.class) {
  26.879 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
  26.880 +            }
  26.881 +
  26.882 +            Object instance = instanceMap.get(getName());
  26.883 +            if (instance != null) {
  26.884 +                return instance;
  26.885 +            } else {
  26.886 +                throw new InvalidObjectException("unknown attribute name");
  26.887 +            }
  26.888 +        }
  26.889 +
  26.890 +        //
  26.891 +        // The constants
  26.892 +        //
  26.893 +
  26.894 +        /**
  26.895 +         * Constant identifying the era field.
  26.896 +         */
  26.897 +        public final static Field ERA = new Field("era", Calendar.ERA);
  26.898 +
  26.899 +        /**
  26.900 +         * Constant identifying the year field.
  26.901 +         */
  26.902 +        public final static Field YEAR = new Field("year", Calendar.YEAR);
  26.903 +
  26.904 +        /**
  26.905 +         * Constant identifying the month field.
  26.906 +         */
  26.907 +        public final static Field MONTH = new Field("month", Calendar.MONTH);
  26.908 +
  26.909 +        /**
  26.910 +         * Constant identifying the day of month field.
  26.911 +         */
  26.912 +        public final static Field DAY_OF_MONTH = new
  26.913 +                            Field("day of month", Calendar.DAY_OF_MONTH);
  26.914 +
  26.915 +        /**
  26.916 +         * Constant identifying the hour of day field, where the legal values
  26.917 +         * are 1 to 24.
  26.918 +         */
  26.919 +        public final static Field HOUR_OF_DAY1 = new Field("hour of day 1",-1);
  26.920 +
  26.921 +        /**
  26.922 +         * Constant identifying the hour of day field, where the legal values
  26.923 +         * are 0 to 23.
  26.924 +         */
  26.925 +        public final static Field HOUR_OF_DAY0 = new
  26.926 +               Field("hour of day", Calendar.HOUR_OF_DAY);
  26.927 +
  26.928 +        /**
  26.929 +         * Constant identifying the minute field.
  26.930 +         */
  26.931 +        public final static Field MINUTE =new Field("minute", Calendar.MINUTE);
  26.932 +
  26.933 +        /**
  26.934 +         * Constant identifying the second field.
  26.935 +         */
  26.936 +        public final static Field SECOND =new Field("second", Calendar.SECOND);
  26.937 +
  26.938 +        /**
  26.939 +         * Constant identifying the millisecond field.
  26.940 +         */
  26.941 +        public final static Field MILLISECOND = new
  26.942 +                Field("millisecond", Calendar.MILLISECOND);
  26.943 +
  26.944 +        /**
  26.945 +         * Constant identifying the day of week field.
  26.946 +         */
  26.947 +        public final static Field DAY_OF_WEEK = new
  26.948 +                Field("day of week", Calendar.DAY_OF_WEEK);
  26.949 +
  26.950 +        /**
  26.951 +         * Constant identifying the day of year field.
  26.952 +         */
  26.953 +        public final static Field DAY_OF_YEAR = new
  26.954 +                Field("day of year", Calendar.DAY_OF_YEAR);
  26.955 +
  26.956 +        /**
  26.957 +         * Constant identifying the day of week field.
  26.958 +         */
  26.959 +        public final static Field DAY_OF_WEEK_IN_MONTH =
  26.960 +                     new Field("day of week in month",
  26.961 +                                            Calendar.DAY_OF_WEEK_IN_MONTH);
  26.962 +
  26.963 +        /**
  26.964 +         * Constant identifying the week of year field.
  26.965 +         */
  26.966 +        public final static Field WEEK_OF_YEAR = new
  26.967 +              Field("week of year", Calendar.WEEK_OF_YEAR);
  26.968 +
  26.969 +        /**
  26.970 +         * Constant identifying the week of month field.
  26.971 +         */
  26.972 +        public final static Field WEEK_OF_MONTH = new
  26.973 +            Field("week of month", Calendar.WEEK_OF_MONTH);
  26.974 +
  26.975 +        /**
  26.976 +         * Constant identifying the time of day indicator
  26.977 +         * (e.g. "a.m." or "p.m.") field.
  26.978 +         */
  26.979 +        public final static Field AM_PM = new
  26.980 +                            Field("am pm", Calendar.AM_PM);
  26.981 +
  26.982 +        /**
  26.983 +         * Constant identifying the hour field, where the legal values are
  26.984 +         * 1 to 12.
  26.985 +         */
  26.986 +        public final static Field HOUR1 = new Field("hour 1", -1);
  26.987 +
  26.988 +        /**
  26.989 +         * Constant identifying the hour field, where the legal values are
  26.990 +         * 0 to 11.
  26.991 +         */
  26.992 +        public final static Field HOUR0 = new
  26.993 +                            Field("hour", Calendar.HOUR);
  26.994 +
  26.995 +        /**
  26.996 +         * Constant identifying the time zone field.
  26.997 +         */
  26.998 +        public final static Field TIME_ZONE = new Field("time zone", -1);
  26.999 +    }
 26.1000 +
 26.1001 +    /**
 26.1002 +     * Obtains a DateFormat instance from a DateFormatProvider
 26.1003 +     * implementation.
 26.1004 +     */
 26.1005 +    private static class DateFormatGetter
 26.1006 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatProvider, DateFormat> {
 26.1007 +        private static final DateFormatGetter INSTANCE = new DateFormatGetter();
 26.1008 +
 26.1009 +        public DateFormat getObject(DateFormatProvider dateFormatProvider,
 26.1010 +                                Locale locale,
 26.1011 +                                String key,
 26.1012 +                                Object... params) {
 26.1013 +            assert params.length == 3;
 26.1014 +
 26.1015 +            int timeStyle = (Integer)params[0];
 26.1016 +            int dateStyle = (Integer)params[1];
 26.1017 +            int flags = (Integer)params[2];
 26.1018 +
 26.1019 +            switch (flags) {
 26.1020 +            case 1:
 26.1021 +                return dateFormatProvider.getTimeInstance(timeStyle, locale);
 26.1022 +            case 2:
 26.1023 +                return dateFormatProvider.getDateInstance(dateStyle, locale);
 26.1024 +            case 3:
 26.1025 +                return dateFormatProvider.getDateTimeInstance(dateStyle, timeStyle, locale);
 26.1026 +            default:
 26.1027 +                assert false : "should not happen";
 26.1028 +            }
 26.1029 +
 26.1030 +            return null;
 26.1031 +        }
 26.1032 +    }
 26.1033 +}
    27.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    27.2 +++ b/rt/emul/compact/src/main/java/java/text/DateFormatSymbols.java	Thu Oct 03 15:40:35 2013 +0200
    27.3 @@ -0,0 +1,794 @@
    27.4 +/*
    27.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
    27.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    27.7 + *
    27.8 + * This code is free software; you can redistribute it and/or modify it
    27.9 + * under the terms of the GNU General Public License version 2 only, as
   27.10 + * published by the Free Software Foundation.  Oracle designates this
   27.11 + * particular file as subject to the "Classpath" exception as provided
   27.12 + * by Oracle in the LICENSE file that accompanied this code.
   27.13 + *
   27.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   27.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   27.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   27.17 + * version 2 for more details (a copy is included in the LICENSE file that
   27.18 + * accompanied this code).
   27.19 + *
   27.20 + * You should have received a copy of the GNU General Public License version
   27.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   27.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   27.23 + *
   27.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   27.25 + * or visit www.oracle.com if you need additional information or have any
   27.26 + * questions.
   27.27 + */
   27.28 +
   27.29 +/*
   27.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   27.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   27.32 + *
   27.33 + *   The original version of this source code and documentation is copyrighted
   27.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   27.35 + * materials are provided under terms of a License Agreement between Taligent
   27.36 + * and Sun. This technology is protected by multiple US and International
   27.37 + * patents. This notice and attribution to Taligent may not be removed.
   27.38 + *   Taligent is a registered trademark of Taligent, Inc.
   27.39 + *
   27.40 + */
   27.41 +
   27.42 +package java.text;
   27.43 +
   27.44 +import java.io.IOException;
   27.45 +import java.io.ObjectOutputStream;
   27.46 +import java.io.Serializable;
   27.47 +import java.lang.ref.SoftReference;
   27.48 +import java.text.spi.DateFormatSymbolsProvider;
   27.49 +import java.util.Arrays;
   27.50 +import java.util.List;
   27.51 +import java.util.Locale;
   27.52 +import java.util.ResourceBundle;
   27.53 +import java.util.TimeZone;
   27.54 +import java.util.concurrent.ConcurrentHashMap;
   27.55 +import java.util.concurrent.ConcurrentMap;
   27.56 +import java.util.spi.LocaleServiceProvider;
   27.57 +import sun.util.LocaleServiceProviderPool;
   27.58 +import sun.util.TimeZoneNameUtility;
   27.59 +import sun.util.calendar.ZoneInfo;
   27.60 +import sun.util.resources.LocaleData;
   27.61 +
   27.62 +/**
   27.63 + * <code>DateFormatSymbols</code> is a public class for encapsulating
   27.64 + * localizable date-time formatting data, such as the names of the
   27.65 + * months, the names of the days of the week, and the time zone data.
   27.66 + * <code>DateFormat</code> and <code>SimpleDateFormat</code> both use
   27.67 + * <code>DateFormatSymbols</code> to encapsulate this information.
   27.68 + *
   27.69 + * <p>
   27.70 + * Typically you shouldn't use <code>DateFormatSymbols</code> directly.
   27.71 + * Rather, you are encouraged to create a date-time formatter with the
   27.72 + * <code>DateFormat</code> class's factory methods: <code>getTimeInstance</code>,
   27.73 + * <code>getDateInstance</code>, or <code>getDateTimeInstance</code>.
   27.74 + * These methods automatically create a <code>DateFormatSymbols</code> for
   27.75 + * the formatter so that you don't have to. After the
   27.76 + * formatter is created, you may modify its format pattern using the
   27.77 + * <code>setPattern</code> method. For more information about
   27.78 + * creating formatters using <code>DateFormat</code>'s factory methods,
   27.79 + * see {@link DateFormat}.
   27.80 + *
   27.81 + * <p>
   27.82 + * If you decide to create a date-time formatter with a specific
   27.83 + * format pattern for a specific locale, you can do so with:
   27.84 + * <blockquote>
   27.85 + * <pre>
   27.86 + * new SimpleDateFormat(aPattern, DateFormatSymbols.getInstance(aLocale)).
   27.87 + * </pre>
   27.88 + * </blockquote>
   27.89 + *
   27.90 + * <p>
   27.91 + * <code>DateFormatSymbols</code> objects are cloneable. When you obtain
   27.92 + * a <code>DateFormatSymbols</code> object, feel free to modify the
   27.93 + * date-time formatting data. For instance, you can replace the localized
   27.94 + * date-time format pattern characters with the ones that you feel easy
   27.95 + * to remember. Or you can change the representative cities
   27.96 + * to your favorite ones.
   27.97 + *
   27.98 + * <p>
   27.99 + * New <code>DateFormatSymbols</code> subclasses may be added to support
  27.100 + * <code>SimpleDateFormat</code> for date-time formatting for additional locales.
  27.101 +
  27.102 + * @see          DateFormat
  27.103 + * @see          SimpleDateFormat
  27.104 + * @see          java.util.SimpleTimeZone
  27.105 + * @author       Chen-Lieh Huang
  27.106 + */
  27.107 +public class DateFormatSymbols implements Serializable, Cloneable {
  27.108 +
  27.109 +    /**
  27.110 +     * Construct a DateFormatSymbols object by loading format data from
  27.111 +     * resources for the default locale. This constructor can only
  27.112 +     * construct instances for the locales supported by the Java
  27.113 +     * runtime environment, not for those supported by installed
  27.114 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
  27.115 +     * implementations. For full locale coverage, use the
  27.116 +     * {@link #getInstance(Locale) getInstance} method.
  27.117 +     *
  27.118 +     * @see #getInstance()
  27.119 +     * @exception  java.util.MissingResourceException
  27.120 +     *             if the resources for the default locale cannot be
  27.121 +     *             found or cannot be loaded.
  27.122 +     */
  27.123 +    public DateFormatSymbols()
  27.124 +    {
  27.125 +        initializeData(Locale.getDefault(Locale.Category.FORMAT));
  27.126 +    }
  27.127 +
  27.128 +    /**
  27.129 +     * Construct a DateFormatSymbols object by loading format data from
  27.130 +     * resources for the given locale. This constructor can only
  27.131 +     * construct instances for the locales supported by the Java
  27.132 +     * runtime environment, not for those supported by installed
  27.133 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
  27.134 +     * implementations. For full locale coverage, use the
  27.135 +     * {@link #getInstance(Locale) getInstance} method.
  27.136 +     *
  27.137 +     * @see #getInstance(Locale)
  27.138 +     * @exception  java.util.MissingResourceException
  27.139 +     *             if the resources for the specified locale cannot be
  27.140 +     *             found or cannot be loaded.
  27.141 +     */
  27.142 +    public DateFormatSymbols(Locale locale)
  27.143 +    {
  27.144 +        initializeData(locale);
  27.145 +    }
  27.146 +
  27.147 +    /**
  27.148 +     * Era strings. For example: "AD" and "BC".  An array of 2 strings,
  27.149 +     * indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>.
  27.150 +     * @serial
  27.151 +     */
  27.152 +    String eras[] = null;
  27.153 +
  27.154 +    /**
  27.155 +     * Month strings. For example: "January", "February", etc.  An array
  27.156 +     * of 13 strings (some calendars have 13 months), indexed by
  27.157 +     * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
  27.158 +     * @serial
  27.159 +     */
  27.160 +    String months[] = null;
  27.161 +
  27.162 +    /**
  27.163 +     * Short month strings. For example: "Jan", "Feb", etc.  An array of
  27.164 +     * 13 strings (some calendars have 13 months), indexed by
  27.165 +     * <code>Calendar.JANUARY</code>, <code>Calendar.FEBRUARY</code>, etc.
  27.166 +
  27.167 +     * @serial
  27.168 +     */
  27.169 +    String shortMonths[] = null;
  27.170 +
  27.171 +    /**
  27.172 +     * Weekday strings. For example: "Sunday", "Monday", etc.  An array
  27.173 +     * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
  27.174 +     * <code>Calendar.MONDAY</code>, etc.
  27.175 +     * The element <code>weekdays[0]</code> is ignored.
  27.176 +     * @serial
  27.177 +     */
  27.178 +    String weekdays[] = null;
  27.179 +
  27.180 +    /**
  27.181 +     * Short weekday strings. For example: "Sun", "Mon", etc.  An array
  27.182 +     * of 8 strings, indexed by <code>Calendar.SUNDAY</code>,
  27.183 +     * <code>Calendar.MONDAY</code>, etc.
  27.184 +     * The element <code>shortWeekdays[0]</code> is ignored.
  27.185 +     * @serial
  27.186 +     */
  27.187 +    String shortWeekdays[] = null;
  27.188 +
  27.189 +    /**
  27.190 +     * AM and PM strings. For example: "AM" and "PM".  An array of
  27.191 +     * 2 strings, indexed by <code>Calendar.AM</code> and
  27.192 +     * <code>Calendar.PM</code>.
  27.193 +     * @serial
  27.194 +     */
  27.195 +    String ampms[] = null;
  27.196 +
  27.197 +    /**
  27.198 +     * Localized names of time zones in this locale.  This is a
  27.199 +     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
  27.200 +     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
  27.201 +     * entry containing the localized names for a single <code>TimeZone</code>.
  27.202 +     * Each such row contains (with <code>i</code> ranging from
  27.203 +     * 0..<em>n</em>-1):
  27.204 +     * <ul>
  27.205 +     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
  27.206 +     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
  27.207 +     * time</li>
  27.208 +     * <li><code>zoneStrings[i][2]</code> - short name of zone in
  27.209 +     * standard time</li>
  27.210 +     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
  27.211 +     * saving time</li>
  27.212 +     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
  27.213 +     * saving time</li>
  27.214 +     * </ul>
  27.215 +     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
  27.216 +     * the {@link java.util.TimeZone TimeZone} class that are not
  27.217 +     * <a href="../java/util/TimeZone.html#CustomID">custom IDs</a>.
  27.218 +     * All other entries are localized names.
  27.219 +     * @see java.util.TimeZone
  27.220 +     * @serial
  27.221 +     */
  27.222 +    String zoneStrings[][] = null;
  27.223 +
  27.224 +    /**
  27.225 +     * Indicates that zoneStrings is set externally with setZoneStrings() method.
  27.226 +     */
  27.227 +    transient boolean isZoneStringsSet = false;
  27.228 +
  27.229 +    /**
  27.230 +     * Unlocalized date-time pattern characters. For example: 'y', 'd', etc.
  27.231 +     * All locales use the same these unlocalized pattern characters.
  27.232 +     */
  27.233 +    static final String  patternChars = "GyMdkHmsSEDFwWahKzZYuX";
  27.234 +
  27.235 +    static final int PATTERN_ERA                  =  0; // G
  27.236 +    static final int PATTERN_YEAR                 =  1; // y
  27.237 +    static final int PATTERN_MONTH                =  2; // M
  27.238 +    static final int PATTERN_DAY_OF_MONTH         =  3; // d
  27.239 +    static final int PATTERN_HOUR_OF_DAY1         =  4; // k
  27.240 +    static final int PATTERN_HOUR_OF_DAY0         =  5; // H
  27.241 +    static final int PATTERN_MINUTE               =  6; // m
  27.242 +    static final int PATTERN_SECOND               =  7; // s
  27.243 +    static final int PATTERN_MILLISECOND          =  8; // S
  27.244 +    static final int PATTERN_DAY_OF_WEEK          =  9; // E
  27.245 +    static final int PATTERN_DAY_OF_YEAR          = 10; // D
  27.246 +    static final int PATTERN_DAY_OF_WEEK_IN_MONTH = 11; // F
  27.247 +    static final int PATTERN_WEEK_OF_YEAR         = 12; // w
  27.248 +    static final int PATTERN_WEEK_OF_MONTH        = 13; // W
  27.249 +    static final int PATTERN_AM_PM                = 14; // a
  27.250 +    static final int PATTERN_HOUR1                = 15; // h
  27.251 +    static final int PATTERN_HOUR0                = 16; // K
  27.252 +    static final int PATTERN_ZONE_NAME            = 17; // z
  27.253 +    static final int PATTERN_ZONE_VALUE           = 18; // Z
  27.254 +    static final int PATTERN_WEEK_YEAR            = 19; // Y
  27.255 +    static final int PATTERN_ISO_DAY_OF_WEEK      = 20; // u
  27.256 +    static final int PATTERN_ISO_ZONE             = 21; // X
  27.257 +
  27.258 +    /**
  27.259 +     * Localized date-time pattern characters. For example, a locale may
  27.260 +     * wish to use 'u' rather than 'y' to represent years in its date format
  27.261 +     * pattern strings.
  27.262 +     * This string must be exactly 18 characters long, with the index of
  27.263 +     * the characters described by <code>DateFormat.ERA_FIELD</code>,
  27.264 +     * <code>DateFormat.YEAR_FIELD</code>, etc.  Thus, if the string were
  27.265 +     * "Xz...", then localized patterns would use 'X' for era and 'z' for year.
  27.266 +     * @serial
  27.267 +     */
  27.268 +    String  localPatternChars = null;
  27.269 +
  27.270 +    /**
  27.271 +     * The locale which is used for initializing this DateFormatSymbols object.
  27.272 +     *
  27.273 +     * @since 1.6
  27.274 +     * @serial
  27.275 +     */
  27.276 +    Locale locale = null;
  27.277 +
  27.278 +    /* use serialVersionUID from JDK 1.1.4 for interoperability */
  27.279 +    static final long serialVersionUID = -5987973545549424702L;
  27.280 +
  27.281 +    /**
  27.282 +     * Returns an array of all locales for which the
  27.283 +     * <code>getInstance</code> methods of this class can return
  27.284 +     * localized instances.
  27.285 +     * The returned array represents the union of locales supported by the
  27.286 +     * Java runtime and by installed
  27.287 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
  27.288 +     * implementations.  It must contain at least a <code>Locale</code>
  27.289 +     * instance equal to {@link java.util.Locale#US Locale.US}.
  27.290 +     *
  27.291 +     * @return An array of locales for which localized
  27.292 +     *         <code>DateFormatSymbols</code> instances are available.
  27.293 +     * @since 1.6
  27.294 +     */
  27.295 +    public static Locale[] getAvailableLocales() {
  27.296 +        LocaleServiceProviderPool pool=
  27.297 +            LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
  27.298 +        return pool.getAvailableLocales();
  27.299 +    }
  27.300 +
  27.301 +    /**
  27.302 +     * Gets the <code>DateFormatSymbols</code> instance for the default
  27.303 +     * locale.  This method provides access to <code>DateFormatSymbols</code>
  27.304 +     * instances for locales supported by the Java runtime itself as well
  27.305 +     * as for those supported by installed
  27.306 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
  27.307 +     * implementations.
  27.308 +     * @return a <code>DateFormatSymbols</code> instance.
  27.309 +     * @since 1.6
  27.310 +     */
  27.311 +    public static final DateFormatSymbols getInstance() {
  27.312 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT));
  27.313 +    }
  27.314 +
  27.315 +    /**
  27.316 +     * Gets the <code>DateFormatSymbols</code> instance for the specified
  27.317 +     * locale.  This method provides access to <code>DateFormatSymbols</code>
  27.318 +     * instances for locales supported by the Java runtime itself as well
  27.319 +     * as for those supported by installed
  27.320 +     * {@link java.text.spi.DateFormatSymbolsProvider DateFormatSymbolsProvider}
  27.321 +     * implementations.
  27.322 +     * @param locale the given locale.
  27.323 +     * @return a <code>DateFormatSymbols</code> instance.
  27.324 +     * @exception NullPointerException if <code>locale</code> is null
  27.325 +     * @since 1.6
  27.326 +     */
  27.327 +    public static final DateFormatSymbols getInstance(Locale locale) {
  27.328 +        DateFormatSymbols dfs = getProviderInstance(locale);
  27.329 +        if (dfs != null) {
  27.330 +            return dfs;
  27.331 +        }
  27.332 +        return (DateFormatSymbols) getCachedInstance(locale).clone();
  27.333 +    }
  27.334 +
  27.335 +    /**
  27.336 +     * Returns a DateFormatSymbols provided by a provider or found in
  27.337 +     * the cache. Note that this method returns a cached instance,
  27.338 +     * not its clone. Therefore, the instance should never be given to
  27.339 +     * an application.
  27.340 +     */
  27.341 +    static final DateFormatSymbols getInstanceRef(Locale locale) {
  27.342 +        DateFormatSymbols dfs = getProviderInstance(locale);
  27.343 +        if (dfs != null) {
  27.344 +            return dfs;
  27.345 +        }
  27.346 +        return getCachedInstance(locale);
  27.347 +    }
  27.348 +
  27.349 +    private static DateFormatSymbols getProviderInstance(Locale locale) {
  27.350 +        DateFormatSymbols providersInstance = null;
  27.351 +
  27.352 +        // Check whether a provider can provide an implementation that's closer
  27.353 +        // to the requested locale than what the Java runtime itself can provide.
  27.354 +        LocaleServiceProviderPool pool =
  27.355 +            LocaleServiceProviderPool.getPool(DateFormatSymbolsProvider.class);
  27.356 +        if (pool.hasProviders()) {
  27.357 +            providersInstance = pool.getLocalizedObject(
  27.358 +                                    DateFormatSymbolsGetter.INSTANCE, locale);
  27.359 +        }
  27.360 +        return providersInstance;
  27.361 +    }
  27.362 +
  27.363 +    /**
  27.364 +     * Returns a cached DateFormatSymbols if it's found in the
  27.365 +     * cache. Otherwise, this method returns a newly cached instance
  27.366 +     * for the given locale.
  27.367 +     */
  27.368 +    private static DateFormatSymbols getCachedInstance(Locale locale) {
  27.369 +        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
  27.370 +        DateFormatSymbols dfs = null;
  27.371 +        if (ref == null || (dfs = ref.get()) == null) {
  27.372 +            dfs = new DateFormatSymbols(locale);
  27.373 +            ref = new SoftReference<DateFormatSymbols>(dfs);
  27.374 +            SoftReference<DateFormatSymbols> x = cachedInstances.putIfAbsent(locale, ref);
  27.375 +            if (x != null) {
  27.376 +                DateFormatSymbols y = x.get();
  27.377 +                if (y != null) {
  27.378 +                    dfs = y;
  27.379 +                } else {
  27.380 +                    // Replace the empty SoftReference with ref.
  27.381 +                    cachedInstances.put(locale, ref);
  27.382 +                }
  27.383 +            }
  27.384 +        }
  27.385 +        return dfs;
  27.386 +    }
  27.387 +
  27.388 +    /**
  27.389 +     * Gets era strings. For example: "AD" and "BC".
  27.390 +     * @return the era strings.
  27.391 +     */
  27.392 +    public String[] getEras() {
  27.393 +        return Arrays.copyOf(eras, eras.length);
  27.394 +    }
  27.395 +
  27.396 +    /**
  27.397 +     * Sets era strings. For example: "AD" and "BC".
  27.398 +     * @param newEras the new era strings.
  27.399 +     */
  27.400 +    public void setEras(String[] newEras) {
  27.401 +        eras = Arrays.copyOf(newEras, newEras.length);
  27.402 +    }
  27.403 +
  27.404 +    /**
  27.405 +     * Gets month strings. For example: "January", "February", etc.
  27.406 +     * @return the month strings.
  27.407 +     */
  27.408 +    public String[] getMonths() {
  27.409 +        return Arrays.copyOf(months, months.length);
  27.410 +    }
  27.411 +
  27.412 +    /**
  27.413 +     * Sets month strings. For example: "January", "February", etc.
  27.414 +     * @param newMonths the new month strings.
  27.415 +     */
  27.416 +    public void setMonths(String[] newMonths) {
  27.417 +        months = Arrays.copyOf(newMonths, newMonths.length);
  27.418 +    }
  27.419 +
  27.420 +    /**
  27.421 +     * Gets short month strings. For example: "Jan", "Feb", etc.
  27.422 +     * @return the short month strings.
  27.423 +     */
  27.424 +    public String[] getShortMonths() {
  27.425 +        return Arrays.copyOf(shortMonths, shortMonths.length);
  27.426 +    }
  27.427 +
  27.428 +    /**
  27.429 +     * Sets short month strings. For example: "Jan", "Feb", etc.
  27.430 +     * @param newShortMonths the new short month strings.
  27.431 +     */
  27.432 +    public void setShortMonths(String[] newShortMonths) {
  27.433 +        shortMonths = Arrays.copyOf(newShortMonths, newShortMonths.length);
  27.434 +    }
  27.435 +
  27.436 +    /**
  27.437 +     * Gets weekday strings. For example: "Sunday", "Monday", etc.
  27.438 +     * @return the weekday strings. Use <code>Calendar.SUNDAY</code>,
  27.439 +     * <code>Calendar.MONDAY</code>, etc. to index the result array.
  27.440 +     */
  27.441 +    public String[] getWeekdays() {
  27.442 +        return Arrays.copyOf(weekdays, weekdays.length);
  27.443 +    }
  27.444 +
  27.445 +    /**
  27.446 +     * Sets weekday strings. For example: "Sunday", "Monday", etc.
  27.447 +     * @param newWeekdays the new weekday strings. The array should
  27.448 +     * be indexed by <code>Calendar.SUNDAY</code>,
  27.449 +     * <code>Calendar.MONDAY</code>, etc.
  27.450 +     */
  27.451 +    public void setWeekdays(String[] newWeekdays) {
  27.452 +        weekdays = Arrays.copyOf(newWeekdays, newWeekdays.length);
  27.453 +    }
  27.454 +
  27.455 +    /**
  27.456 +     * Gets short weekday strings. For example: "Sun", "Mon", etc.
  27.457 +     * @return the short weekday strings. Use <code>Calendar.SUNDAY</code>,
  27.458 +     * <code>Calendar.MONDAY</code>, etc. to index the result array.
  27.459 +     */
  27.460 +    public String[] getShortWeekdays() {
  27.461 +        return Arrays.copyOf(shortWeekdays, shortWeekdays.length);
  27.462 +    }
  27.463 +
  27.464 +    /**
  27.465 +     * Sets short weekday strings. For example: "Sun", "Mon", etc.
  27.466 +     * @param newShortWeekdays the new short weekday strings. The array should
  27.467 +     * be indexed by <code>Calendar.SUNDAY</code>,
  27.468 +     * <code>Calendar.MONDAY</code>, etc.
  27.469 +     */
  27.470 +    public void setShortWeekdays(String[] newShortWeekdays) {
  27.471 +        shortWeekdays = Arrays.copyOf(newShortWeekdays, newShortWeekdays.length);
  27.472 +    }
  27.473 +
  27.474 +    /**
  27.475 +     * Gets ampm strings. For example: "AM" and "PM".
  27.476 +     * @return the ampm strings.
  27.477 +     */
  27.478 +    public String[] getAmPmStrings() {
  27.479 +        return Arrays.copyOf(ampms, ampms.length);
  27.480 +    }
  27.481 +
  27.482 +    /**
  27.483 +     * Sets ampm strings. For example: "AM" and "PM".
  27.484 +     * @param newAmpms the new ampm strings.
  27.485 +     */
  27.486 +    public void setAmPmStrings(String[] newAmpms) {
  27.487 +        ampms = Arrays.copyOf(newAmpms, newAmpms.length);
  27.488 +    }
  27.489 +
  27.490 +    /**
  27.491 +     * Gets time zone strings.  Use of this method is discouraged; use
  27.492 +     * {@link java.util.TimeZone#getDisplayName() TimeZone.getDisplayName()}
  27.493 +     * instead.
  27.494 +     * <p>
  27.495 +     * The value returned is a
  27.496 +     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
  27.497 +     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
  27.498 +     * entry containing the localized names for a single <code>TimeZone</code>.
  27.499 +     * Each such row contains (with <code>i</code> ranging from
  27.500 +     * 0..<em>n</em>-1):
  27.501 +     * <ul>
  27.502 +     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
  27.503 +     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
  27.504 +     * time</li>
  27.505 +     * <li><code>zoneStrings[i][2]</code> - short name of zone in
  27.506 +     * standard time</li>
  27.507 +     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
  27.508 +     * saving time</li>
  27.509 +     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
  27.510 +     * saving time</li>
  27.511 +     * </ul>
  27.512 +     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
  27.513 +     * the {@link java.util.TimeZone TimeZone} class that are not
  27.514 +     * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
  27.515 +     * All other entries are localized names.  If a zone does not implement
  27.516 +     * daylight saving time, the daylight saving time names should not be used.
  27.517 +     * <p>
  27.518 +     * If {@link #setZoneStrings(String[][]) setZoneStrings} has been called
  27.519 +     * on this <code>DateFormatSymbols</code> instance, then the strings
  27.520 +     * provided by that call are returned. Otherwise, the returned array
  27.521 +     * contains names provided by the Java runtime and by installed
  27.522 +     * {@link java.util.spi.TimeZoneNameProvider TimeZoneNameProvider}
  27.523 +     * implementations.
  27.524 +     *
  27.525 +     * @return the time zone strings.
  27.526 +     * @see #setZoneStrings(String[][])
  27.527 +     */
  27.528 +    public String[][] getZoneStrings() {
  27.529 +        return getZoneStringsImpl(true);
  27.530 +    }
  27.531 +
  27.532 +    /**
  27.533 +     * Sets time zone strings.  The argument must be a
  27.534 +     * two-dimensional array of strings of size <em>n</em> by <em>m</em>,
  27.535 +     * where <em>m</em> is at least 5.  Each of the <em>n</em> rows is an
  27.536 +     * entry containing the localized names for a single <code>TimeZone</code>.
  27.537 +     * Each such row contains (with <code>i</code> ranging from
  27.538 +     * 0..<em>n</em>-1):
  27.539 +     * <ul>
  27.540 +     * <li><code>zoneStrings[i][0]</code> - time zone ID</li>
  27.541 +     * <li><code>zoneStrings[i][1]</code> - long name of zone in standard
  27.542 +     * time</li>
  27.543 +     * <li><code>zoneStrings[i][2]</code> - short name of zone in
  27.544 +     * standard time</li>
  27.545 +     * <li><code>zoneStrings[i][3]</code> - long name of zone in daylight
  27.546 +     * saving time</li>
  27.547 +     * <li><code>zoneStrings[i][4]</code> - short name of zone in daylight
  27.548 +     * saving time</li>
  27.549 +     * </ul>
  27.550 +     * The zone ID is <em>not</em> localized; it's one of the valid IDs of
  27.551 +     * the {@link java.util.TimeZone TimeZone} class that are not
  27.552 +     * <a href="../util/TimeZone.html#CustomID">custom IDs</a>.
  27.553 +     * All other entries are localized names.
  27.554 +     *
  27.555 +     * @param newZoneStrings the new time zone strings.
  27.556 +     * @exception IllegalArgumentException if the length of any row in
  27.557 +     *    <code>newZoneStrings</code> is less than 5
  27.558 +     * @exception NullPointerException if <code>newZoneStrings</code> is null
  27.559 +     * @see #getZoneStrings()
  27.560 +     */
  27.561 +    public void setZoneStrings(String[][] newZoneStrings) {
  27.562 +        String[][] aCopy = new String[newZoneStrings.length][];
  27.563 +        for (int i = 0; i < newZoneStrings.length; ++i) {
  27.564 +            int len = newZoneStrings[i].length;
  27.565 +            if (len < 5) {
  27.566 +                throw new IllegalArgumentException();
  27.567 +            }
  27.568 +            aCopy[i] = Arrays.copyOf(newZoneStrings[i], len);
  27.569 +        }
  27.570 +        zoneStrings = aCopy;
  27.571 +        isZoneStringsSet = true;
  27.572 +    }
  27.573 +
  27.574 +    /**
  27.575 +     * Gets localized date-time pattern characters. For example: 'u', 't', etc.
  27.576 +     * @return the localized date-time pattern characters.
  27.577 +     */
  27.578 +    public String getLocalPatternChars() {
  27.579 +        return localPatternChars;
  27.580 +    }
  27.581 +
  27.582 +    /**
  27.583 +     * Sets localized date-time pattern characters. For example: 'u', 't', etc.
  27.584 +     * @param newLocalPatternChars the new localized date-time
  27.585 +     * pattern characters.
  27.586 +     */
  27.587 +    public void setLocalPatternChars(String newLocalPatternChars) {
  27.588 +        // Call toString() to throw an NPE in case the argument is null
  27.589 +        localPatternChars = newLocalPatternChars.toString();
  27.590 +    }
  27.591 +
  27.592 +    /**
  27.593 +     * Overrides Cloneable
  27.594 +     */
  27.595 +    public Object clone()
  27.596 +    {
  27.597 +        try
  27.598 +        {
  27.599 +            DateFormatSymbols other = (DateFormatSymbols)super.clone();
  27.600 +            copyMembers(this, other);
  27.601 +            return other;
  27.602 +        } catch (CloneNotSupportedException e) {
  27.603 +            throw new InternalError();
  27.604 +        }
  27.605 +    }
  27.606 +
  27.607 +    /**
  27.608 +     * Override hashCode.
  27.609 +     * Generates a hash code for the DateFormatSymbols object.
  27.610 +     */
  27.611 +    public int hashCode() {
  27.612 +        int hashcode = 0;
  27.613 +        String[][] zoneStrings = getZoneStringsWrapper();
  27.614 +        for (int index = 0; index < zoneStrings[0].length; ++index)
  27.615 +            hashcode ^= zoneStrings[0][index].hashCode();
  27.616 +        return hashcode;
  27.617 +    }
  27.618 +
  27.619 +    /**
  27.620 +     * Override equals
  27.621 +     */
  27.622 +    public boolean equals(Object obj)
  27.623 +    {
  27.624 +        if (this == obj) return true;
  27.625 +        if (obj == null || getClass() != obj.getClass()) return false;
  27.626 +        DateFormatSymbols that = (DateFormatSymbols) obj;
  27.627 +        return (Arrays.equals(eras, that.eras)
  27.628 +                && Arrays.equals(months, that.months)
  27.629 +                && Arrays.equals(shortMonths, that.shortMonths)
  27.630 +                && Arrays.equals(weekdays, that.weekdays)
  27.631 +                && Arrays.equals(shortWeekdays, that.shortWeekdays)
  27.632 +                && Arrays.equals(ampms, that.ampms)
  27.633 +                && Arrays.deepEquals(getZoneStringsWrapper(), that.getZoneStringsWrapper())
  27.634 +                && ((localPatternChars != null
  27.635 +                  && localPatternChars.equals(that.localPatternChars))
  27.636 +                 || (localPatternChars == null
  27.637 +                  && that.localPatternChars == null)));
  27.638 +    }
  27.639 +
  27.640 +    // =======================privates===============================
  27.641 +
  27.642 +    /**
  27.643 +     * Useful constant for defining time zone offsets.
  27.644 +     */
  27.645 +    static final int millisPerHour = 60*60*1000;
  27.646 +
  27.647 +    /**
  27.648 +     * Cache to hold DateFormatSymbols instances per Locale.
  27.649 +     */
  27.650 +    private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances
  27.651 +        = new ConcurrentHashMap<Locale, SoftReference<DateFormatSymbols>>(3);
  27.652 +
  27.653 +    private void initializeData(Locale desiredLocale) {
  27.654 +        locale = desiredLocale;
  27.655 +
  27.656 +        // Copy values of a cached instance if any.
  27.657 +        SoftReference<DateFormatSymbols> ref = cachedInstances.get(locale);
  27.658 +        DateFormatSymbols dfs;
  27.659 +        if (ref != null && (dfs = ref.get()) != null) {
  27.660 +            copyMembers(dfs, this);
  27.661 +            return;
  27.662 +        }
  27.663 +
  27.664 +        // Initialize the fields from the ResourceBundle for locale.
  27.665 +        ResourceBundle resource = LocaleData.getDateFormatData(locale);
  27.666 +
  27.667 +        eras = resource.getStringArray("Eras");
  27.668 +        months = resource.getStringArray("MonthNames");
  27.669 +        shortMonths = resource.getStringArray("MonthAbbreviations");
  27.670 +        ampms = resource.getStringArray("AmPmMarkers");
  27.671 +        localPatternChars = resource.getString("DateTimePatternChars");
  27.672 +
  27.673 +        // Day of week names are stored in a 1-based array.
  27.674 +        weekdays = toOneBasedArray(resource.getStringArray("DayNames"));
  27.675 +        shortWeekdays = toOneBasedArray(resource.getStringArray("DayAbbreviations"));
  27.676 +    }
  27.677 +
  27.678 +    private static String[] toOneBasedArray(String[] src) {
  27.679 +        int len = src.length;
  27.680 +        String[] dst = new String[len + 1];
  27.681 +        dst[0] = "";
  27.682 +        for (int i = 0; i < len; i++) {
  27.683 +            dst[i + 1] = src[i];
  27.684 +        }
  27.685 +        return dst;
  27.686 +    }
  27.687 +
  27.688 +    /**
  27.689 +     * Package private: used by SimpleDateFormat
  27.690 +     * Gets the index for the given time zone ID to obtain the time zone
  27.691 +     * strings for formatting. The time zone ID is just for programmatic
  27.692 +     * lookup. NOT LOCALIZED!!!
  27.693 +     * @param ID the given time zone ID.
  27.694 +     * @return the index of the given time zone ID.  Returns -1 if
  27.695 +     * the given time zone ID can't be located in the DateFormatSymbols object.
  27.696 +     * @see java.util.SimpleTimeZone
  27.697 +     */
  27.698 +    final int getZoneIndex(String ID)
  27.699 +    {
  27.700 +        String[][] zoneStrings = getZoneStringsWrapper();
  27.701 +        for (int index=0; index<zoneStrings.length; index++)
  27.702 +        {
  27.703 +            if (ID.equals(zoneStrings[index][0])) return index;
  27.704 +        }
  27.705 +
  27.706 +        return -1;
  27.707 +    }
  27.708 +
  27.709 +    /**
  27.710 +     * Wrapper method to the getZoneStrings(), which is called from inside
  27.711 +     * the java.text package and not to mutate the returned arrays, so that
  27.712 +     * it does not need to create a defensive copy.
  27.713 +     */
  27.714 +    final String[][] getZoneStringsWrapper() {
  27.715 +        if (isSubclassObject()) {
  27.716 +            return getZoneStrings();
  27.717 +        } else {
  27.718 +            return getZoneStringsImpl(false);
  27.719 +        }
  27.720 +    }
  27.721 +
  27.722 +    private final String[][] getZoneStringsImpl(boolean needsCopy) {
  27.723 +        if (zoneStrings == null) {
  27.724 +            zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
  27.725 +        }
  27.726 +
  27.727 +        if (!needsCopy) {
  27.728 +            return zoneStrings;
  27.729 +        }
  27.730 +
  27.731 +        int len = zoneStrings.length;
  27.732 +        String[][] aCopy = new String[len][];
  27.733 +        for (int i = 0; i < len; i++) {
  27.734 +            aCopy[i] = Arrays.copyOf(zoneStrings[i], zoneStrings[i].length);
  27.735 +        }
  27.736 +        return aCopy;
  27.737 +    }
  27.738 +
  27.739 +    private final boolean isSubclassObject() {
  27.740 +        return !getClass().getName().equals("java.text.DateFormatSymbols");
  27.741 +    }
  27.742 +
  27.743 +    /**
  27.744 +     * Clones all the data members from the source DateFormatSymbols to
  27.745 +     * the target DateFormatSymbols. This is only for subclasses.
  27.746 +     * @param src the source DateFormatSymbols.
  27.747 +     * @param dst the target DateFormatSymbols.
  27.748 +     */
  27.749 +    private final void copyMembers(DateFormatSymbols src, DateFormatSymbols dst)
  27.750 +    {
  27.751 +        dst.eras = Arrays.copyOf(src.eras, src.eras.length);
  27.752 +        dst.months = Arrays.copyOf(src.months, src.months.length);
  27.753 +        dst.shortMonths = Arrays.copyOf(src.shortMonths, src.shortMonths.length);
  27.754 +        dst.weekdays = Arrays.copyOf(src.weekdays, src.weekdays.length);
  27.755 +        dst.shortWeekdays = Arrays.copyOf(src.shortWeekdays, src.shortWeekdays.length);
  27.756 +        dst.ampms = Arrays.copyOf(src.ampms, src.ampms.length);
  27.757 +        if (src.zoneStrings != null) {
  27.758 +            dst.zoneStrings = src.getZoneStringsImpl(true);
  27.759 +        } else {
  27.760 +            dst.zoneStrings = null;
  27.761 +        }
  27.762 +        dst.localPatternChars = src.localPatternChars;
  27.763 +    }
  27.764 +
  27.765 +    /**
  27.766 +     * Write out the default serializable data, after ensuring the
  27.767 +     * <code>zoneStrings</code> field is initialized in order to make
  27.768 +     * sure the backward compatibility.
  27.769 +     *
  27.770 +     * @since 1.6
  27.771 +     */
  27.772 +    private void writeObject(ObjectOutputStream stream) throws IOException {
  27.773 +        if (zoneStrings == null) {
  27.774 +            zoneStrings = TimeZoneNameUtility.getZoneStrings(locale);
  27.775 +        }
  27.776 +        stream.defaultWriteObject();
  27.777 +    }
  27.778 +
  27.779 +    /**
  27.780 +     * Obtains a DateFormatSymbols instance from a DateFormatSymbolsProvider
  27.781 +     * implementation.
  27.782 +     */
  27.783 +    private static class DateFormatSymbolsGetter
  27.784 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<DateFormatSymbolsProvider,
  27.785 +                                                                   DateFormatSymbols> {
  27.786 +        private static final DateFormatSymbolsGetter INSTANCE =
  27.787 +            new DateFormatSymbolsGetter();
  27.788 +
  27.789 +        public DateFormatSymbols getObject(DateFormatSymbolsProvider dateFormatSymbolsProvider,
  27.790 +                                Locale locale,
  27.791 +                                String key,
  27.792 +                                Object... params) {
  27.793 +            assert params.length == 0;
  27.794 +            return dateFormatSymbolsProvider.getInstance(locale);
  27.795 +        }
  27.796 +    }
  27.797 +}
    28.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    28.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormat.java	Thu Oct 03 15:40:35 2013 +0200
    28.3 @@ -0,0 +1,3278 @@
    28.4 +/*
    28.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
    28.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    28.7 + *
    28.8 + * This code is free software; you can redistribute it and/or modify it
    28.9 + * under the terms of the GNU General Public License version 2 only, as
   28.10 + * published by the Free Software Foundation.  Oracle designates this
   28.11 + * particular file as subject to the "Classpath" exception as provided
   28.12 + * by Oracle in the LICENSE file that accompanied this code.
   28.13 + *
   28.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   28.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   28.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   28.17 + * version 2 for more details (a copy is included in the LICENSE file that
   28.18 + * accompanied this code).
   28.19 + *
   28.20 + * You should have received a copy of the GNU General Public License version
   28.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   28.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   28.23 + *
   28.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   28.25 + * or visit www.oracle.com if you need additional information or have any
   28.26 + * questions.
   28.27 + */
   28.28 +
   28.29 +/*
   28.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   28.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   28.32 + *
   28.33 + *   The original version of this source code and documentation is copyrighted
   28.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   28.35 + * materials are provided under terms of a License Agreement between Taligent
   28.36 + * and Sun. This technology is protected by multiple US and International
   28.37 + * patents. This notice and attribution to Taligent may not be removed.
   28.38 + *   Taligent is a registered trademark of Taligent, Inc.
   28.39 + *
   28.40 + */
   28.41 +
   28.42 +package java.text;
   28.43 +
   28.44 +import java.io.InvalidObjectException;
   28.45 +import java.io.IOException;
   28.46 +import java.io.ObjectInputStream;
   28.47 +import java.math.BigDecimal;
   28.48 +import java.math.BigInteger;
   28.49 +import java.math.RoundingMode;
   28.50 +import java.util.ArrayList;
   28.51 +import java.util.Currency;
   28.52 +import java.util.Locale;
   28.53 +import java.util.ResourceBundle;
   28.54 +import java.util.concurrent.ConcurrentHashMap;
   28.55 +import java.util.concurrent.ConcurrentMap;
   28.56 +import java.util.concurrent.atomic.AtomicInteger;
   28.57 +import java.util.concurrent.atomic.AtomicLong;
   28.58 +import sun.util.resources.LocaleData;
   28.59 +
   28.60 +/**
   28.61 + * <code>DecimalFormat</code> is a concrete subclass of
   28.62 + * <code>NumberFormat</code> that formats decimal numbers. It has a variety of
   28.63 + * features designed to make it possible to parse and format numbers in any
   28.64 + * locale, including support for Western, Arabic, and Indic digits.  It also
   28.65 + * supports different kinds of numbers, including integers (123), fixed-point
   28.66 + * numbers (123.4), scientific notation (1.23E4), percentages (12%), and
   28.67 + * currency amounts ($123).  All of these can be localized.
   28.68 + *
   28.69 + * <p>To obtain a <code>NumberFormat</code> for a specific locale, including the
   28.70 + * default locale, call one of <code>NumberFormat</code>'s factory methods, such
   28.71 + * as <code>getInstance()</code>.  In general, do not call the
   28.72 + * <code>DecimalFormat</code> constructors directly, since the
   28.73 + * <code>NumberFormat</code> factory methods may return subclasses other than
   28.74 + * <code>DecimalFormat</code>. If you need to customize the format object, do
   28.75 + * something like this:
   28.76 + *
   28.77 + * <blockquote><pre>
   28.78 + * NumberFormat f = NumberFormat.getInstance(loc);
   28.79 + * if (f instanceof DecimalFormat) {
   28.80 + *     ((DecimalFormat) f).setDecimalSeparatorAlwaysShown(true);
   28.81 + * }
   28.82 + * </pre></blockquote>
   28.83 + *
   28.84 + * <p>A <code>DecimalFormat</code> comprises a <em>pattern</em> and a set of
   28.85 + * <em>symbols</em>.  The pattern may be set directly using
   28.86 + * <code>applyPattern()</code>, or indirectly using the API methods.  The
   28.87 + * symbols are stored in a <code>DecimalFormatSymbols</code> object.  When using
   28.88 + * the <code>NumberFormat</code> factory methods, the pattern and symbols are
   28.89 + * read from localized <code>ResourceBundle</code>s.
   28.90 + *
   28.91 + * <h4>Patterns</h4>
   28.92 + *
   28.93 + * <code>DecimalFormat</code> patterns have the following syntax:
   28.94 + * <blockquote><pre>
   28.95 + * <i>Pattern:</i>
   28.96 + *         <i>PositivePattern</i>
   28.97 + *         <i>PositivePattern</i> ; <i>NegativePattern</i>
   28.98 + * <i>PositivePattern:</i>
   28.99 + *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
  28.100 + * <i>NegativePattern:</i>
  28.101 + *         <i>Prefix<sub>opt</sub></i> <i>Number</i> <i>Suffix<sub>opt</sub></i>
  28.102 + * <i>Prefix:</i>
  28.103 + *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
  28.104 + * <i>Suffix:</i>
  28.105 + *         any Unicode characters except &#92;uFFFE, &#92;uFFFF, and special characters
  28.106 + * <i>Number:</i>
  28.107 + *         <i>Integer</i> <i>Exponent<sub>opt</sub></i>
  28.108 + *         <i>Integer</i> . <i>Fraction</i> <i>Exponent<sub>opt</sub></i>
  28.109 + * <i>Integer:</i>
  28.110 + *         <i>MinimumInteger</i>
  28.111 + *         #
  28.112 + *         # <i>Integer</i>
  28.113 + *         # , <i>Integer</i>
  28.114 + * <i>MinimumInteger:</i>
  28.115 + *         0
  28.116 + *         0 <i>MinimumInteger</i>
  28.117 + *         0 , <i>MinimumInteger</i>
  28.118 + * <i>Fraction:</i>
  28.119 + *         <i>MinimumFraction<sub>opt</sub></i> <i>OptionalFraction<sub>opt</sub></i>
  28.120 + * <i>MinimumFraction:</i>
  28.121 + *         0 <i>MinimumFraction<sub>opt</sub></i>
  28.122 + * <i>OptionalFraction:</i>
  28.123 + *         # <i>OptionalFraction<sub>opt</sub></i>
  28.124 + * <i>Exponent:</i>
  28.125 + *         E <i>MinimumExponent</i>
  28.126 + * <i>MinimumExponent:</i>
  28.127 + *         0 <i>MinimumExponent<sub>opt</sub></i>
  28.128 + * </pre></blockquote>
  28.129 + *
  28.130 + * <p>A <code>DecimalFormat</code> pattern contains a positive and negative
  28.131 + * subpattern, for example, <code>"#,##0.00;(#,##0.00)"</code>.  Each
  28.132 + * subpattern has a prefix, numeric part, and suffix. The negative subpattern
  28.133 + * is optional; if absent, then the positive subpattern prefixed with the
  28.134 + * localized minus sign (<code>'-'</code> in most locales) is used as the
  28.135 + * negative subpattern. That is, <code>"0.00"</code> alone is equivalent to
  28.136 + * <code>"0.00;-0.00"</code>.  If there is an explicit negative subpattern, it
  28.137 + * serves only to specify the negative prefix and suffix; the number of digits,
  28.138 + * minimal digits, and other characteristics are all the same as the positive
  28.139 + * pattern. That means that <code>"#,##0.0#;(#)"</code> produces precisely
  28.140 + * the same behavior as <code>"#,##0.0#;(#,##0.0#)"</code>.
  28.141 + *
  28.142 + * <p>The prefixes, suffixes, and various symbols used for infinity, digits,
  28.143 + * thousands separators, decimal separators, etc. may be set to arbitrary
  28.144 + * values, and they will appear properly during formatting.  However, care must
  28.145 + * be taken that the symbols and strings do not conflict, or parsing will be
  28.146 + * unreliable.  For example, either the positive and negative prefixes or the
  28.147 + * suffixes must be distinct for <code>DecimalFormat.parse()</code> to be able
  28.148 + * to distinguish positive from negative values.  (If they are identical, then
  28.149 + * <code>DecimalFormat</code> will behave as if no negative subpattern was
  28.150 + * specified.)  Another example is that the decimal separator and thousands
  28.151 + * separator should be distinct characters, or parsing will be impossible.
  28.152 + *
  28.153 + * <p>The grouping separator is commonly used for thousands, but in some
  28.154 + * countries it separates ten-thousands. The grouping size is a constant number
  28.155 + * of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
  28.156 + * 1,0000,0000.  If you supply a pattern with multiple grouping characters, the
  28.157 + * interval between the last one and the end of the integer is the one that is
  28.158 + * used. So <code>"#,##,###,####"</code> == <code>"######,####"</code> ==
  28.159 + * <code>"##,####,####"</code>.
  28.160 + *
  28.161 + * <h4>Special Pattern Characters</h4>
  28.162 + *
  28.163 + * <p>Many characters in a pattern are taken literally; they are matched during
  28.164 + * parsing and output unchanged during formatting.  Special characters, on the
  28.165 + * other hand, stand for other characters, strings, or classes of characters.
  28.166 + * They must be quoted, unless noted otherwise, if they are to appear in the
  28.167 + * prefix or suffix as literals.
  28.168 + *
  28.169 + * <p>The characters listed here are used in non-localized patterns.  Localized
  28.170 + * patterns use the corresponding characters taken from this formatter's
  28.171 + * <code>DecimalFormatSymbols</code> object instead, and these characters lose
  28.172 + * their special status.  Two exceptions are the currency sign and quote, which
  28.173 + * are not localized.
  28.174 + *
  28.175 + * <blockquote>
  28.176 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart showing symbol,
  28.177 + *  location, localized, and meaning.">
  28.178 + *     <tr bgcolor="#ccccff">
  28.179 + *          <th align=left>Symbol
  28.180 + *          <th align=left>Location
  28.181 + *          <th align=left>Localized?
  28.182 + *          <th align=left>Meaning
  28.183 + *     <tr valign=top>
  28.184 + *          <td><code>0</code>
  28.185 + *          <td>Number
  28.186 + *          <td>Yes
  28.187 + *          <td>Digit
  28.188 + *     <tr valign=top bgcolor="#eeeeff">
  28.189 + *          <td><code>#</code>
  28.190 + *          <td>Number
  28.191 + *          <td>Yes
  28.192 + *          <td>Digit, zero shows as absent
  28.193 + *     <tr valign=top>
  28.194 + *          <td><code>.</code>
  28.195 + *          <td>Number
  28.196 + *          <td>Yes
  28.197 + *          <td>Decimal separator or monetary decimal separator
  28.198 + *     <tr valign=top bgcolor="#eeeeff">
  28.199 + *          <td><code>-</code>
  28.200 + *          <td>Number
  28.201 + *          <td>Yes
  28.202 + *          <td>Minus sign
  28.203 + *     <tr valign=top>
  28.204 + *          <td><code>,</code>
  28.205 + *          <td>Number
  28.206 + *          <td>Yes
  28.207 + *          <td>Grouping separator
  28.208 + *     <tr valign=top bgcolor="#eeeeff">
  28.209 + *          <td><code>E</code>
  28.210 + *          <td>Number
  28.211 + *          <td>Yes
  28.212 + *          <td>Separates mantissa and exponent in scientific notation.
  28.213 + *              <em>Need not be quoted in prefix or suffix.</em>
  28.214 + *     <tr valign=top>
  28.215 + *          <td><code>;</code>
  28.216 + *          <td>Subpattern boundary
  28.217 + *          <td>Yes
  28.218 + *          <td>Separates positive and negative subpatterns
  28.219 + *     <tr valign=top bgcolor="#eeeeff">
  28.220 + *          <td><code>%</code>
  28.221 + *          <td>Prefix or suffix
  28.222 + *          <td>Yes
  28.223 + *          <td>Multiply by 100 and show as percentage
  28.224 + *     <tr valign=top>
  28.225 + *          <td><code>&#92;u2030</code>
  28.226 + *          <td>Prefix or suffix
  28.227 + *          <td>Yes
  28.228 + *          <td>Multiply by 1000 and show as per mille value
  28.229 + *     <tr valign=top bgcolor="#eeeeff">
  28.230 + *          <td><code>&#164;</code> (<code>&#92;u00A4</code>)
  28.231 + *          <td>Prefix or suffix
  28.232 + *          <td>No
  28.233 + *          <td>Currency sign, replaced by currency symbol.  If
  28.234 + *              doubled, replaced by international currency symbol.
  28.235 + *              If present in a pattern, the monetary decimal separator
  28.236 + *              is used instead of the decimal separator.
  28.237 + *     <tr valign=top>
  28.238 + *          <td><code>'</code>
  28.239 + *          <td>Prefix or suffix
  28.240 + *          <td>No
  28.241 + *          <td>Used to quote special characters in a prefix or suffix,
  28.242 + *              for example, <code>"'#'#"</code> formats 123 to
  28.243 + *              <code>"#123"</code>.  To create a single quote
  28.244 + *              itself, use two in a row: <code>"# o''clock"</code>.
  28.245 + * </table>
  28.246 + * </blockquote>
  28.247 + *
  28.248 + * <h4>Scientific Notation</h4>
  28.249 + *
  28.250 + * <p>Numbers in scientific notation are expressed as the product of a mantissa
  28.251 + * and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3.  The
  28.252 + * mantissa is often in the range 1.0 <= x < 10.0, but it need not be.
  28.253 + * <code>DecimalFormat</code> can be instructed to format and parse scientific
  28.254 + * notation <em>only via a pattern</em>; there is currently no factory method
  28.255 + * that creates a scientific notation format.  In a pattern, the exponent
  28.256 + * character immediately followed by one or more digit characters indicates
  28.257 + * scientific notation.  Example: <code>"0.###E0"</code> formats the number
  28.258 + * 1234 as <code>"1.234E3"</code>.
  28.259 + *
  28.260 + * <ul>
  28.261 + * <li>The number of digit characters after the exponent character gives the
  28.262 + * minimum exponent digit count.  There is no maximum.  Negative exponents are
  28.263 + * formatted using the localized minus sign, <em>not</em> the prefix and suffix
  28.264 + * from the pattern.  This allows patterns such as <code>"0.###E0 m/s"</code>.
  28.265 + *
  28.266 + * <li>The minimum and maximum number of integer digits are interpreted
  28.267 + * together:
  28.268 + *
  28.269 + * <ul>
  28.270 + * <li>If the maximum number of integer digits is greater than their minimum number
  28.271 + * and greater than 1, it forces the exponent to be a multiple of the maximum
  28.272 + * number of integer digits, and the minimum number of integer digits to be
  28.273 + * interpreted as 1.  The most common use of this is to generate
  28.274 + * <em>engineering notation</em>, in which the exponent is a multiple of three,
  28.275 + * e.g., <code>"##0.#####E0"</code>. Using this pattern, the number 12345
  28.276 + * formats to <code>"12.345E3"</code>, and 123456 formats to
  28.277 + * <code>"123.456E3"</code>.
  28.278 + *
  28.279 + * <li>Otherwise, the minimum number of integer digits is achieved by adjusting the
  28.280 + * exponent.  Example: 0.00123 formatted with <code>"00.###E0"</code> yields
  28.281 + * <code>"12.3E-4"</code>.
  28.282 + * </ul>
  28.283 + *
  28.284 + * <li>The number of significant digits in the mantissa is the sum of the
  28.285 + * <em>minimum integer</em> and <em>maximum fraction</em> digits, and is
  28.286 + * unaffected by the maximum integer digits.  For example, 12345 formatted with
  28.287 + * <code>"##0.##E0"</code> is <code>"12.3E3"</code>. To show all digits, set
  28.288 + * the significant digits count to zero.  The number of significant digits
  28.289 + * does not affect parsing.
  28.290 + *
  28.291 + * <li>Exponential patterns may not contain grouping separators.
  28.292 + * </ul>
  28.293 + *
  28.294 + * <h4>Rounding</h4>
  28.295 + *
  28.296 + * <code>DecimalFormat</code> provides rounding modes defined in
  28.297 + * {@link java.math.RoundingMode} for formatting.  By default, it uses
  28.298 + * {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
  28.299 + *
  28.300 + * <h4>Digits</h4>
  28.301 + *
  28.302 + * For formatting, <code>DecimalFormat</code> uses the ten consecutive
  28.303 + * characters starting with the localized zero digit defined in the
  28.304 + * <code>DecimalFormatSymbols</code> object as digits. For parsing, these
  28.305 + * digits as well as all Unicode decimal digits, as defined by
  28.306 + * {@link Character#digit Character.digit}, are recognized.
  28.307 + *
  28.308 + * <h4>Special Values</h4>
  28.309 + *
  28.310 + * <p><code>NaN</code> is formatted as a string, which typically has a single character
  28.311 + * <code>&#92;uFFFD</code>.  This string is determined by the
  28.312 + * <code>DecimalFormatSymbols</code> object.  This is the only value for which
  28.313 + * the prefixes and suffixes are not used.
  28.314 + *
  28.315 + * <p>Infinity is formatted as a string, which typically has a single character
  28.316 + * <code>&#92;u221E</code>, with the positive or negative prefixes and suffixes
  28.317 + * applied.  The infinity string is determined by the
  28.318 + * <code>DecimalFormatSymbols</code> object.
  28.319 + *
  28.320 + * <p>Negative zero (<code>"-0"</code>) parses to
  28.321 + * <ul>
  28.322 + * <li><code>BigDecimal(0)</code> if <code>isParseBigDecimal()</code> is
  28.323 + * true,
  28.324 + * <li><code>Long(0)</code> if <code>isParseBigDecimal()</code> is false
  28.325 + *     and <code>isParseIntegerOnly()</code> is true,
  28.326 + * <li><code>Double(-0.0)</code> if both <code>isParseBigDecimal()</code>
  28.327 + * and <code>isParseIntegerOnly()</code> are false.
  28.328 + * </ul>
  28.329 + *
  28.330 + * <h4><a name="synchronization">Synchronization</a></h4>
  28.331 + *
  28.332 + * <p>
  28.333 + * Decimal formats are generally not synchronized.
  28.334 + * It is recommended to create separate format instances for each thread.
  28.335 + * If multiple threads access a format concurrently, it must be synchronized
  28.336 + * externally.
  28.337 + *
  28.338 + * <h4>Example</h4>
  28.339 + *
  28.340 + * <blockquote><pre>
  28.341 + * <strong>// Print out a number using the localized number, integer, currency,
  28.342 + * // and percent format for each locale</strong>
  28.343 + * Locale[] locales = NumberFormat.getAvailableLocales();
  28.344 + * double myNumber = -1234.56;
  28.345 + * NumberFormat form;
  28.346 + * for (int j=0; j<4; ++j) {
  28.347 + *     System.out.println("FORMAT");
  28.348 + *     for (int i = 0; i < locales.length; ++i) {
  28.349 + *         if (locales[i].getCountry().length() == 0) {
  28.350 + *            continue; // Skip language-only locales
  28.351 + *         }
  28.352 + *         System.out.print(locales[i].getDisplayName());
  28.353 + *         switch (j) {
  28.354 + *         case 0:
  28.355 + *             form = NumberFormat.getInstance(locales[i]); break;
  28.356 + *         case 1:
  28.357 + *             form = NumberFormat.getIntegerInstance(locales[i]); break;
  28.358 + *         case 2:
  28.359 + *             form = NumberFormat.getCurrencyInstance(locales[i]); break;
  28.360 + *         default:
  28.361 + *             form = NumberFormat.getPercentInstance(locales[i]); break;
  28.362 + *         }
  28.363 + *         if (form instanceof DecimalFormat) {
  28.364 + *             System.out.print(": " + ((DecimalFormat) form).toPattern());
  28.365 + *         }
  28.366 + *         System.out.print(" -> " + form.format(myNumber));
  28.367 + *         try {
  28.368 + *             System.out.println(" -> " + form.parse(form.format(myNumber)));
  28.369 + *         } catch (ParseException e) {}
  28.370 + *     }
  28.371 + * }
  28.372 + * </pre></blockquote>
  28.373 + *
  28.374 + * @see          <a href="http://java.sun.com/docs/books/tutorial/i18n/format/decimalFormat.html">Java Tutorial</a>
  28.375 + * @see          NumberFormat
  28.376 + * @see          DecimalFormatSymbols
  28.377 + * @see          ParsePosition
  28.378 + * @author       Mark Davis
  28.379 + * @author       Alan Liu
  28.380 + */
  28.381 +public class DecimalFormat extends NumberFormat {
  28.382 +
  28.383 +    /**
  28.384 +     * Creates a DecimalFormat using the default pattern and symbols
  28.385 +     * for the default locale. This is a convenient way to obtain a
  28.386 +     * DecimalFormat when internationalization is not the main concern.
  28.387 +     * <p>
  28.388 +     * To obtain standard formats for a given locale, use the factory methods
  28.389 +     * on NumberFormat such as getNumberInstance. These factories will
  28.390 +     * return the most appropriate sub-class of NumberFormat for a given
  28.391 +     * locale.
  28.392 +     *
  28.393 +     * @see java.text.NumberFormat#getInstance
  28.394 +     * @see java.text.NumberFormat#getNumberInstance
  28.395 +     * @see java.text.NumberFormat#getCurrencyInstance
  28.396 +     * @see java.text.NumberFormat#getPercentInstance
  28.397 +     */
  28.398 +    public DecimalFormat() {
  28.399 +        Locale def = Locale.getDefault(Locale.Category.FORMAT);
  28.400 +        // try to get the pattern from the cache
  28.401 +        String pattern = cachedLocaleData.get(def);
  28.402 +        if (pattern == null) {  /* cache miss */
  28.403 +            // Get the pattern for the default locale.
  28.404 +            ResourceBundle rb = LocaleData.getNumberFormatData(def);
  28.405 +            String[] all = rb.getStringArray("NumberPatterns");
  28.406 +            pattern = all[0];
  28.407 +            /* update cache */
  28.408 +            cachedLocaleData.putIfAbsent(def, pattern);
  28.409 +        }
  28.410 +
  28.411 +        // Always applyPattern after the symbols are set
  28.412 +        this.symbols = new DecimalFormatSymbols(def);
  28.413 +        applyPattern(pattern, false);
  28.414 +    }
  28.415 +
  28.416 +
  28.417 +    /**
  28.418 +     * Creates a DecimalFormat using the given pattern and the symbols
  28.419 +     * for the default locale. This is a convenient way to obtain a
  28.420 +     * DecimalFormat when internationalization is not the main concern.
  28.421 +     * <p>
  28.422 +     * To obtain standard formats for a given locale, use the factory methods
  28.423 +     * on NumberFormat such as getNumberInstance. These factories will
  28.424 +     * return the most appropriate sub-class of NumberFormat for a given
  28.425 +     * locale.
  28.426 +     *
  28.427 +     * @param pattern A non-localized pattern string.
  28.428 +     * @exception NullPointerException if <code>pattern</code> is null
  28.429 +     * @exception IllegalArgumentException if the given pattern is invalid.
  28.430 +     * @see java.text.NumberFormat#getInstance
  28.431 +     * @see java.text.NumberFormat#getNumberInstance
  28.432 +     * @see java.text.NumberFormat#getCurrencyInstance
  28.433 +     * @see java.text.NumberFormat#getPercentInstance
  28.434 +     */
  28.435 +    public DecimalFormat(String pattern) {
  28.436 +        // Always applyPattern after the symbols are set
  28.437 +        this.symbols = new DecimalFormatSymbols(Locale.getDefault(Locale.Category.FORMAT));
  28.438 +        applyPattern(pattern, false);
  28.439 +    }
  28.440 +
  28.441 +
  28.442 +    /**
  28.443 +     * Creates a DecimalFormat using the given pattern and symbols.
  28.444 +     * Use this constructor when you need to completely customize the
  28.445 +     * behavior of the format.
  28.446 +     * <p>
  28.447 +     * To obtain standard formats for a given
  28.448 +     * locale, use the factory methods on NumberFormat such as
  28.449 +     * getInstance or getCurrencyInstance. If you need only minor adjustments
  28.450 +     * to a standard format, you can modify the format returned by
  28.451 +     * a NumberFormat factory method.
  28.452 +     *
  28.453 +     * @param pattern a non-localized pattern string
  28.454 +     * @param symbols the set of symbols to be used
  28.455 +     * @exception NullPointerException if any of the given arguments is null
  28.456 +     * @exception IllegalArgumentException if the given pattern is invalid
  28.457 +     * @see java.text.NumberFormat#getInstance
  28.458 +     * @see java.text.NumberFormat#getNumberInstance
  28.459 +     * @see java.text.NumberFormat#getCurrencyInstance
  28.460 +     * @see java.text.NumberFormat#getPercentInstance
  28.461 +     * @see java.text.DecimalFormatSymbols
  28.462 +     */
  28.463 +    public DecimalFormat (String pattern, DecimalFormatSymbols symbols) {
  28.464 +        // Always applyPattern after the symbols are set
  28.465 +        this.symbols = (DecimalFormatSymbols)symbols.clone();
  28.466 +        applyPattern(pattern, false);
  28.467 +    }
  28.468 +
  28.469 +
  28.470 +    // Overrides
  28.471 +    /**
  28.472 +     * Formats a number and appends the resulting text to the given string
  28.473 +     * buffer.
  28.474 +     * The number can be of any subclass of {@link java.lang.Number}.
  28.475 +     * <p>
  28.476 +     * This implementation uses the maximum precision permitted.
  28.477 +     * @param number     the number to format
  28.478 +     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
  28.479 +     *                   text is to be appended
  28.480 +     * @param pos        On input: an alignment field, if desired.
  28.481 +     *                   On output: the offsets of the alignment field.
  28.482 +     * @return           the value passed in as <code>toAppendTo</code>
  28.483 +     * @exception        IllegalArgumentException if <code>number</code> is
  28.484 +     *                   null or not an instance of <code>Number</code>.
  28.485 +     * @exception        NullPointerException if <code>toAppendTo</code> or
  28.486 +     *                   <code>pos</code> is null
  28.487 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.488 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.489 +     * @see              java.text.FieldPosition
  28.490 +     */
  28.491 +    public final StringBuffer format(Object number,
  28.492 +                                     StringBuffer toAppendTo,
  28.493 +                                     FieldPosition pos) {
  28.494 +        if (number instanceof Long || number instanceof Integer ||
  28.495 +                   number instanceof Short || number instanceof Byte ||
  28.496 +                   number instanceof AtomicInteger ||
  28.497 +                   number instanceof AtomicLong ||
  28.498 +                   (number instanceof BigInteger &&
  28.499 +                    ((BigInteger)number).bitLength () < 64)) {
  28.500 +            return format(((Number)number).longValue(), toAppendTo, pos);
  28.501 +        } else if (number instanceof BigDecimal) {
  28.502 +            return format((BigDecimal)number, toAppendTo, pos);
  28.503 +        } else if (number instanceof BigInteger) {
  28.504 +            return format((BigInteger)number, toAppendTo, pos);
  28.505 +        } else if (number instanceof Number) {
  28.506 +            return format(((Number)number).doubleValue(), toAppendTo, pos);
  28.507 +        } else {
  28.508 +            throw new IllegalArgumentException("Cannot format given Object as a Number");
  28.509 +        }
  28.510 +    }
  28.511 +
  28.512 +    /**
  28.513 +     * Formats a double to produce a string.
  28.514 +     * @param number    The double to format
  28.515 +     * @param result    where the text is to be appended
  28.516 +     * @param fieldPosition    On input: an alignment field, if desired.
  28.517 +     * On output: the offsets of the alignment field.
  28.518 +     * @exception ArithmeticException if rounding is needed with rounding
  28.519 +     *            mode being set to RoundingMode.UNNECESSARY
  28.520 +     * @return The formatted number string
  28.521 +     * @see java.text.FieldPosition
  28.522 +     */
  28.523 +    public StringBuffer format(double number, StringBuffer result,
  28.524 +                               FieldPosition fieldPosition) {
  28.525 +        fieldPosition.setBeginIndex(0);
  28.526 +        fieldPosition.setEndIndex(0);
  28.527 +
  28.528 +        return format(number, result, fieldPosition.getFieldDelegate());
  28.529 +    }
  28.530 +
  28.531 +    /**
  28.532 +     * Formats a double to produce a string.
  28.533 +     * @param number    The double to format
  28.534 +     * @param result    where the text is to be appended
  28.535 +     * @param delegate notified of locations of sub fields
  28.536 +     * @exception       ArithmeticException if rounding is needed with rounding
  28.537 +     *                  mode being set to RoundingMode.UNNECESSARY
  28.538 +     * @return The formatted number string
  28.539 +     */
  28.540 +    private StringBuffer format(double number, StringBuffer result,
  28.541 +                                FieldDelegate delegate) {
  28.542 +        if (Double.isNaN(number) ||
  28.543 +           (Double.isInfinite(number) && multiplier == 0)) {
  28.544 +            int iFieldStart = result.length();
  28.545 +            result.append(symbols.getNaN());
  28.546 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
  28.547 +                               iFieldStart, result.length(), result);
  28.548 +            return result;
  28.549 +        }
  28.550 +
  28.551 +        /* Detecting whether a double is negative is easy with the exception of
  28.552 +         * the value -0.0.  This is a double which has a zero mantissa (and
  28.553 +         * exponent), but a negative sign bit.  It is semantically distinct from
  28.554 +         * a zero with a positive sign bit, and this distinction is important
  28.555 +         * to certain kinds of computations.  However, it's a little tricky to
  28.556 +         * detect, since (-0.0 == 0.0) and !(-0.0 < 0.0).  How then, you may
  28.557 +         * ask, does it behave distinctly from +0.0?  Well, 1/(-0.0) ==
  28.558 +         * -Infinity.  Proper detection of -0.0 is needed to deal with the
  28.559 +         * issues raised by bugs 4106658, 4106667, and 4147706.  Liu 7/6/98.
  28.560 +         */
  28.561 +        boolean isNegative = ((number < 0.0) || (number == 0.0 && 1/number < 0.0)) ^ (multiplier < 0);
  28.562 +
  28.563 +        if (multiplier != 1) {
  28.564 +            number *= multiplier;
  28.565 +        }
  28.566 +
  28.567 +        if (Double.isInfinite(number)) {
  28.568 +            if (isNegative) {
  28.569 +                append(result, negativePrefix, delegate,
  28.570 +                       getNegativePrefixFieldPositions(), Field.SIGN);
  28.571 +            } else {
  28.572 +                append(result, positivePrefix, delegate,
  28.573 +                       getPositivePrefixFieldPositions(), Field.SIGN);
  28.574 +            }
  28.575 +
  28.576 +            int iFieldStart = result.length();
  28.577 +            result.append(symbols.getInfinity());
  28.578 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
  28.579 +                               iFieldStart, result.length(), result);
  28.580 +
  28.581 +            if (isNegative) {
  28.582 +                append(result, negativeSuffix, delegate,
  28.583 +                       getNegativeSuffixFieldPositions(), Field.SIGN);
  28.584 +            } else {
  28.585 +                append(result, positiveSuffix, delegate,
  28.586 +                       getPositiveSuffixFieldPositions(), Field.SIGN);
  28.587 +            }
  28.588 +
  28.589 +            return result;
  28.590 +        }
  28.591 +
  28.592 +        if (isNegative) {
  28.593 +            number = -number;
  28.594 +        }
  28.595 +
  28.596 +        // at this point we are guaranteed a nonnegative finite number.
  28.597 +        assert(number >= 0 && !Double.isInfinite(number));
  28.598 +
  28.599 +        synchronized(digitList) {
  28.600 +            int maxIntDigits = super.getMaximumIntegerDigits();
  28.601 +            int minIntDigits = super.getMinimumIntegerDigits();
  28.602 +            int maxFraDigits = super.getMaximumFractionDigits();
  28.603 +            int minFraDigits = super.getMinimumFractionDigits();
  28.604 +
  28.605 +            digitList.set(isNegative, number, useExponentialNotation ?
  28.606 +                          maxIntDigits + maxFraDigits : maxFraDigits,
  28.607 +                          !useExponentialNotation);
  28.608 +            return subformat(result, delegate, isNegative, false,
  28.609 +                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
  28.610 +        }
  28.611 +    }
  28.612 +
  28.613 +    /**
  28.614 +     * Format a long to produce a string.
  28.615 +     * @param number    The long to format
  28.616 +     * @param result    where the text is to be appended
  28.617 +     * @param fieldPosition    On input: an alignment field, if desired.
  28.618 +     * On output: the offsets of the alignment field.
  28.619 +     * @exception       ArithmeticException if rounding is needed with rounding
  28.620 +     *                  mode being set to RoundingMode.UNNECESSARY
  28.621 +     * @return The formatted number string
  28.622 +     * @see java.text.FieldPosition
  28.623 +     */
  28.624 +    public StringBuffer format(long number, StringBuffer result,
  28.625 +                               FieldPosition fieldPosition) {
  28.626 +        fieldPosition.setBeginIndex(0);
  28.627 +        fieldPosition.setEndIndex(0);
  28.628 +
  28.629 +        return format(number, result, fieldPosition.getFieldDelegate());
  28.630 +    }
  28.631 +
  28.632 +    /**
  28.633 +     * Format a long to produce a string.
  28.634 +     * @param number    The long to format
  28.635 +     * @param result    where the text is to be appended
  28.636 +     * @param delegate notified of locations of sub fields
  28.637 +     * @return The formatted number string
  28.638 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.639 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.640 +     * @see java.text.FieldPosition
  28.641 +     */
  28.642 +    private StringBuffer format(long number, StringBuffer result,
  28.643 +                               FieldDelegate delegate) {
  28.644 +        boolean isNegative = (number < 0);
  28.645 +        if (isNegative) {
  28.646 +            number = -number;
  28.647 +        }
  28.648 +
  28.649 +        // In general, long values always represent real finite numbers, so
  28.650 +        // we don't have to check for +/- Infinity or NaN.  However, there
  28.651 +        // is one case we have to be careful of:  The multiplier can push
  28.652 +        // a number near MIN_VALUE or MAX_VALUE outside the legal range.  We
  28.653 +        // check for this before multiplying, and if it happens we use
  28.654 +        // BigInteger instead.
  28.655 +        boolean useBigInteger = false;
  28.656 +        if (number < 0) { // This can only happen if number == Long.MIN_VALUE.
  28.657 +            if (multiplier != 0) {
  28.658 +                useBigInteger = true;
  28.659 +            }
  28.660 +        } else if (multiplier != 1 && multiplier != 0) {
  28.661 +            long cutoff = Long.MAX_VALUE / multiplier;
  28.662 +            if (cutoff < 0) {
  28.663 +                cutoff = -cutoff;
  28.664 +            }
  28.665 +            useBigInteger = (number > cutoff);
  28.666 +        }
  28.667 +
  28.668 +        if (useBigInteger) {
  28.669 +            if (isNegative) {
  28.670 +                number = -number;
  28.671 +            }
  28.672 +            BigInteger bigIntegerValue = BigInteger.valueOf(number);
  28.673 +            return format(bigIntegerValue, result, delegate, true);
  28.674 +        }
  28.675 +
  28.676 +        number *= multiplier;
  28.677 +        if (number == 0) {
  28.678 +            isNegative = false;
  28.679 +        } else {
  28.680 +            if (multiplier < 0) {
  28.681 +                number = -number;
  28.682 +                isNegative = !isNegative;
  28.683 +            }
  28.684 +        }
  28.685 +
  28.686 +        synchronized(digitList) {
  28.687 +            int maxIntDigits = super.getMaximumIntegerDigits();
  28.688 +            int minIntDigits = super.getMinimumIntegerDigits();
  28.689 +            int maxFraDigits = super.getMaximumFractionDigits();
  28.690 +            int minFraDigits = super.getMinimumFractionDigits();
  28.691 +
  28.692 +            digitList.set(isNegative, number,
  28.693 +                     useExponentialNotation ? maxIntDigits + maxFraDigits : 0);
  28.694 +
  28.695 +            return subformat(result, delegate, isNegative, true,
  28.696 +                       maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
  28.697 +        }
  28.698 +    }
  28.699 +
  28.700 +    /**
  28.701 +     * Formats a BigDecimal to produce a string.
  28.702 +     * @param number    The BigDecimal to format
  28.703 +     * @param result    where the text is to be appended
  28.704 +     * @param fieldPosition    On input: an alignment field, if desired.
  28.705 +     * On output: the offsets of the alignment field.
  28.706 +     * @return The formatted number string
  28.707 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.708 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.709 +     * @see java.text.FieldPosition
  28.710 +     */
  28.711 +    private StringBuffer format(BigDecimal number, StringBuffer result,
  28.712 +                                FieldPosition fieldPosition) {
  28.713 +        fieldPosition.setBeginIndex(0);
  28.714 +        fieldPosition.setEndIndex(0);
  28.715 +        return format(number, result, fieldPosition.getFieldDelegate());
  28.716 +    }
  28.717 +
  28.718 +    /**
  28.719 +     * Formats a BigDecimal to produce a string.
  28.720 +     * @param number    The BigDecimal to format
  28.721 +     * @param result    where the text is to be appended
  28.722 +     * @param delegate notified of locations of sub fields
  28.723 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.724 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.725 +     * @return The formatted number string
  28.726 +     */
  28.727 +    private StringBuffer format(BigDecimal number, StringBuffer result,
  28.728 +                                FieldDelegate delegate) {
  28.729 +        if (multiplier != 1) {
  28.730 +            number = number.multiply(getBigDecimalMultiplier());
  28.731 +        }
  28.732 +        boolean isNegative = number.signum() == -1;
  28.733 +        if (isNegative) {
  28.734 +            number = number.negate();
  28.735 +        }
  28.736 +
  28.737 +        synchronized(digitList) {
  28.738 +            int maxIntDigits = getMaximumIntegerDigits();
  28.739 +            int minIntDigits = getMinimumIntegerDigits();
  28.740 +            int maxFraDigits = getMaximumFractionDigits();
  28.741 +            int minFraDigits = getMinimumFractionDigits();
  28.742 +            int maximumDigits = maxIntDigits + maxFraDigits;
  28.743 +
  28.744 +            digitList.set(isNegative, number, useExponentialNotation ?
  28.745 +                ((maximumDigits < 0) ? Integer.MAX_VALUE : maximumDigits) :
  28.746 +                maxFraDigits, !useExponentialNotation);
  28.747 +
  28.748 +            return subformat(result, delegate, isNegative, false,
  28.749 +                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
  28.750 +        }
  28.751 +    }
  28.752 +
  28.753 +    /**
  28.754 +     * Format a BigInteger to produce a string.
  28.755 +     * @param number    The BigInteger to format
  28.756 +     * @param result    where the text is to be appended
  28.757 +     * @param fieldPosition    On input: an alignment field, if desired.
  28.758 +     * On output: the offsets of the alignment field.
  28.759 +     * @return The formatted number string
  28.760 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.761 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.762 +     * @see java.text.FieldPosition
  28.763 +     */
  28.764 +    private StringBuffer format(BigInteger number, StringBuffer result,
  28.765 +                               FieldPosition fieldPosition) {
  28.766 +        fieldPosition.setBeginIndex(0);
  28.767 +        fieldPosition.setEndIndex(0);
  28.768 +
  28.769 +        return format(number, result, fieldPosition.getFieldDelegate(), false);
  28.770 +    }
  28.771 +
  28.772 +    /**
  28.773 +     * Format a BigInteger to produce a string.
  28.774 +     * @param number    The BigInteger to format
  28.775 +     * @param result    where the text is to be appended
  28.776 +     * @param delegate notified of locations of sub fields
  28.777 +     * @return The formatted number string
  28.778 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.779 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.780 +     * @see java.text.FieldPosition
  28.781 +     */
  28.782 +    private StringBuffer format(BigInteger number, StringBuffer result,
  28.783 +                               FieldDelegate delegate, boolean formatLong) {
  28.784 +        if (multiplier != 1) {
  28.785 +            number = number.multiply(getBigIntegerMultiplier());
  28.786 +        }
  28.787 +        boolean isNegative = number.signum() == -1;
  28.788 +        if (isNegative) {
  28.789 +            number = number.negate();
  28.790 +        }
  28.791 +
  28.792 +        synchronized(digitList) {
  28.793 +            int maxIntDigits, minIntDigits, maxFraDigits, minFraDigits, maximumDigits;
  28.794 +            if (formatLong) {
  28.795 +                maxIntDigits = super.getMaximumIntegerDigits();
  28.796 +                minIntDigits = super.getMinimumIntegerDigits();
  28.797 +                maxFraDigits = super.getMaximumFractionDigits();
  28.798 +                minFraDigits = super.getMinimumFractionDigits();
  28.799 +                maximumDigits = maxIntDigits + maxFraDigits;
  28.800 +            } else {
  28.801 +                maxIntDigits = getMaximumIntegerDigits();
  28.802 +                minIntDigits = getMinimumIntegerDigits();
  28.803 +                maxFraDigits = getMaximumFractionDigits();
  28.804 +                minFraDigits = getMinimumFractionDigits();
  28.805 +                maximumDigits = maxIntDigits + maxFraDigits;
  28.806 +                if (maximumDigits < 0) {
  28.807 +                    maximumDigits = Integer.MAX_VALUE;
  28.808 +                }
  28.809 +            }
  28.810 +
  28.811 +            digitList.set(isNegative, number,
  28.812 +                          useExponentialNotation ? maximumDigits : 0);
  28.813 +
  28.814 +            return subformat(result, delegate, isNegative, true,
  28.815 +                maxIntDigits, minIntDigits, maxFraDigits, minFraDigits);
  28.816 +        }
  28.817 +    }
  28.818 +
  28.819 +    /**
  28.820 +     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
  28.821 +     * You can use the returned <code>AttributedCharacterIterator</code>
  28.822 +     * to build the resulting String, as well as to determine information
  28.823 +     * about the resulting String.
  28.824 +     * <p>
  28.825 +     * Each attribute key of the AttributedCharacterIterator will be of type
  28.826 +     * <code>NumberFormat.Field</code>, with the attribute value being the
  28.827 +     * same as the attribute key.
  28.828 +     *
  28.829 +     * @exception NullPointerException if obj is null.
  28.830 +     * @exception IllegalArgumentException when the Format cannot format the
  28.831 +     *            given object.
  28.832 +     * @exception        ArithmeticException if rounding is needed with rounding
  28.833 +     *                   mode being set to RoundingMode.UNNECESSARY
  28.834 +     * @param obj The object to format
  28.835 +     * @return AttributedCharacterIterator describing the formatted value.
  28.836 +     * @since 1.4
  28.837 +     */
  28.838 +    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
  28.839 +        CharacterIteratorFieldDelegate delegate =
  28.840 +                         new CharacterIteratorFieldDelegate();
  28.841 +        StringBuffer sb = new StringBuffer();
  28.842 +
  28.843 +        if (obj instanceof Double || obj instanceof Float) {
  28.844 +            format(((Number)obj).doubleValue(), sb, delegate);
  28.845 +        } else if (obj instanceof Long || obj instanceof Integer ||
  28.846 +                   obj instanceof Short || obj instanceof Byte ||
  28.847 +                   obj instanceof AtomicInteger || obj instanceof AtomicLong) {
  28.848 +            format(((Number)obj).longValue(), sb, delegate);
  28.849 +        } else if (obj instanceof BigDecimal) {
  28.850 +            format((BigDecimal)obj, sb, delegate);
  28.851 +        } else if (obj instanceof BigInteger) {
  28.852 +            format((BigInteger)obj, sb, delegate, false);
  28.853 +        } else if (obj == null) {
  28.854 +            throw new NullPointerException(
  28.855 +                "formatToCharacterIterator must be passed non-null object");
  28.856 +        } else {
  28.857 +            throw new IllegalArgumentException(
  28.858 +                "Cannot format given Object as a Number");
  28.859 +        }
  28.860 +        return delegate.getIterator(sb.toString());
  28.861 +    }
  28.862 +
  28.863 +    /**
  28.864 +     * Complete the formatting of a finite number.  On entry, the digitList must
  28.865 +     * be filled in with the correct digits.
  28.866 +     */
  28.867 +    private StringBuffer subformat(StringBuffer result, FieldDelegate delegate,
  28.868 +                                   boolean isNegative, boolean isInteger,
  28.869 +                                   int maxIntDigits, int minIntDigits,
  28.870 +                                   int maxFraDigits, int minFraDigits) {
  28.871 +        // NOTE: This isn't required anymore because DigitList takes care of this.
  28.872 +        //
  28.873 +        //  // The negative of the exponent represents the number of leading
  28.874 +        //  // zeros between the decimal and the first non-zero digit, for
  28.875 +        //  // a value < 0.1 (e.g., for 0.00123, -fExponent == 2).  If this
  28.876 +        //  // is more than the maximum fraction digits, then we have an underflow
  28.877 +        //  // for the printed representation.  We recognize this here and set
  28.878 +        //  // the DigitList representation to zero in this situation.
  28.879 +        //
  28.880 +        //  if (-digitList.decimalAt >= getMaximumFractionDigits())
  28.881 +        //  {
  28.882 +        //      digitList.count = 0;
  28.883 +        //  }
  28.884 +
  28.885 +        char zero = symbols.getZeroDigit();
  28.886 +        int zeroDelta = zero - '0'; // '0' is the DigitList representation of zero
  28.887 +        char grouping = symbols.getGroupingSeparator();
  28.888 +        char decimal = isCurrencyFormat ?
  28.889 +            symbols.getMonetaryDecimalSeparator() :
  28.890 +            symbols.getDecimalSeparator();
  28.891 +
  28.892 +        /* Per bug 4147706, DecimalFormat must respect the sign of numbers which
  28.893 +         * format as zero.  This allows sensible computations and preserves
  28.894 +         * relations such as signum(1/x) = signum(x), where x is +Infinity or
  28.895 +         * -Infinity.  Prior to this fix, we always formatted zero values as if
  28.896 +         * they were positive.  Liu 7/6/98.
  28.897 +         */
  28.898 +        if (digitList.isZero()) {
  28.899 +            digitList.decimalAt = 0; // Normalize
  28.900 +        }
  28.901 +
  28.902 +        if (isNegative) {
  28.903 +            append(result, negativePrefix, delegate,
  28.904 +                   getNegativePrefixFieldPositions(), Field.SIGN);
  28.905 +        } else {
  28.906 +            append(result, positivePrefix, delegate,
  28.907 +                   getPositivePrefixFieldPositions(), Field.SIGN);
  28.908 +        }
  28.909 +
  28.910 +        if (useExponentialNotation) {
  28.911 +            int iFieldStart = result.length();
  28.912 +            int iFieldEnd = -1;
  28.913 +            int fFieldStart = -1;
  28.914 +
  28.915 +            // Minimum integer digits are handled in exponential format by
  28.916 +            // adjusting the exponent.  For example, 0.01234 with 3 minimum
  28.917 +            // integer digits is "123.4E-4".
  28.918 +
  28.919 +            // Maximum integer digits are interpreted as indicating the
  28.920 +            // repeating range.  This is useful for engineering notation, in
  28.921 +            // which the exponent is restricted to a multiple of 3.  For
  28.922 +            // example, 0.01234 with 3 maximum integer digits is "12.34e-3".
  28.923 +            // If maximum integer digits are > 1 and are larger than
  28.924 +            // minimum integer digits, then minimum integer digits are
  28.925 +            // ignored.
  28.926 +            int exponent = digitList.decimalAt;
  28.927 +            int repeat = maxIntDigits;
  28.928 +            int minimumIntegerDigits = minIntDigits;
  28.929 +            if (repeat > 1 && repeat > minIntDigits) {
  28.930 +                // A repeating range is defined; adjust to it as follows.
  28.931 +                // If repeat == 3, we have 6,5,4=>3; 3,2,1=>0; 0,-1,-2=>-3;
  28.932 +                // -3,-4,-5=>-6, etc. This takes into account that the
  28.933 +                // exponent we have here is off by one from what we expect;
  28.934 +                // it is for the format 0.MMMMMx10^n.
  28.935 +                if (exponent >= 1) {
  28.936 +                    exponent = ((exponent - 1) / repeat) * repeat;
  28.937 +                } else {
  28.938 +                    // integer division rounds towards 0
  28.939 +                    exponent = ((exponent - repeat) / repeat) * repeat;
  28.940 +                }
  28.941 +                minimumIntegerDigits = 1;
  28.942 +            } else {
  28.943 +                // No repeating range is defined; use minimum integer digits.
  28.944 +                exponent -= minimumIntegerDigits;
  28.945 +            }
  28.946 +
  28.947 +            // We now output a minimum number of digits, and more if there
  28.948 +            // are more digits, up to the maximum number of digits.  We
  28.949 +            // place the decimal point after the "integer" digits, which
  28.950 +            // are the first (decimalAt - exponent) digits.
  28.951 +            int minimumDigits = minIntDigits + minFraDigits;
  28.952 +            if (minimumDigits < 0) {    // overflow?
  28.953 +                minimumDigits = Integer.MAX_VALUE;
  28.954 +            }
  28.955 +
  28.956 +            // The number of integer digits is handled specially if the number
  28.957 +            // is zero, since then there may be no digits.
  28.958 +            int integerDigits = digitList.isZero() ? minimumIntegerDigits :
  28.959 +                    digitList.decimalAt - exponent;
  28.960 +            if (minimumDigits < integerDigits) {
  28.961 +                minimumDigits = integerDigits;
  28.962 +            }
  28.963 +            int totalDigits = digitList.count;
  28.964 +            if (minimumDigits > totalDigits) {
  28.965 +                totalDigits = minimumDigits;
  28.966 +            }
  28.967 +            boolean addedDecimalSeparator = false;
  28.968 +
  28.969 +            for (int i=0; i<totalDigits; ++i) {
  28.970 +                if (i == integerDigits) {
  28.971 +                    // Record field information for caller.
  28.972 +                    iFieldEnd = result.length();
  28.973 +
  28.974 +                    result.append(decimal);
  28.975 +                    addedDecimalSeparator = true;
  28.976 +
  28.977 +                    // Record field information for caller.
  28.978 +                    fFieldStart = result.length();
  28.979 +                }
  28.980 +                result.append((i < digitList.count) ?
  28.981 +                              (char)(digitList.digits[i] + zeroDelta) :
  28.982 +                              zero);
  28.983 +            }
  28.984 +
  28.985 +            if (decimalSeparatorAlwaysShown && totalDigits == integerDigits) {
  28.986 +                // Record field information for caller.
  28.987 +                iFieldEnd = result.length();
  28.988 +
  28.989 +                result.append(decimal);
  28.990 +                addedDecimalSeparator = true;
  28.991 +
  28.992 +                // Record field information for caller.
  28.993 +                fFieldStart = result.length();
  28.994 +            }
  28.995 +
  28.996 +            // Record field information
  28.997 +            if (iFieldEnd == -1) {
  28.998 +                iFieldEnd = result.length();
  28.999 +            }
 28.1000 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
 28.1001 +                               iFieldStart, iFieldEnd, result);
 28.1002 +            if (addedDecimalSeparator) {
 28.1003 +                delegate.formatted(Field.DECIMAL_SEPARATOR,
 28.1004 +                                   Field.DECIMAL_SEPARATOR,
 28.1005 +                                   iFieldEnd, fFieldStart, result);
 28.1006 +            }
 28.1007 +            if (fFieldStart == -1) {
 28.1008 +                fFieldStart = result.length();
 28.1009 +            }
 28.1010 +            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
 28.1011 +                               fFieldStart, result.length(), result);
 28.1012 +
 28.1013 +            // The exponent is output using the pattern-specified minimum
 28.1014 +            // exponent digits.  There is no maximum limit to the exponent
 28.1015 +            // digits, since truncating the exponent would result in an
 28.1016 +            // unacceptable inaccuracy.
 28.1017 +            int fieldStart = result.length();
 28.1018 +
 28.1019 +            result.append(symbols.getExponentSeparator());
 28.1020 +
 28.1021 +            delegate.formatted(Field.EXPONENT_SYMBOL, Field.EXPONENT_SYMBOL,
 28.1022 +                               fieldStart, result.length(), result);
 28.1023 +
 28.1024 +            // For zero values, we force the exponent to zero.  We
 28.1025 +            // must do this here, and not earlier, because the value
 28.1026 +            // is used to determine integer digit count above.
 28.1027 +            if (digitList.isZero()) {
 28.1028 +                exponent = 0;
 28.1029 +            }
 28.1030 +
 28.1031 +            boolean negativeExponent = exponent < 0;
 28.1032 +            if (negativeExponent) {
 28.1033 +                exponent = -exponent;
 28.1034 +                fieldStart = result.length();
 28.1035 +                result.append(symbols.getMinusSign());
 28.1036 +                delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
 28.1037 +                                   fieldStart, result.length(), result);
 28.1038 +            }
 28.1039 +            digitList.set(negativeExponent, exponent);
 28.1040 +
 28.1041 +            int eFieldStart = result.length();
 28.1042 +
 28.1043 +            for (int i=digitList.decimalAt; i<minExponentDigits; ++i) {
 28.1044 +                result.append(zero);
 28.1045 +            }
 28.1046 +            for (int i=0; i<digitList.decimalAt; ++i) {
 28.1047 +                result.append((i < digitList.count) ?
 28.1048 +                          (char)(digitList.digits[i] + zeroDelta) : zero);
 28.1049 +            }
 28.1050 +            delegate.formatted(Field.EXPONENT, Field.EXPONENT, eFieldStart,
 28.1051 +                               result.length(), result);
 28.1052 +        } else {
 28.1053 +            int iFieldStart = result.length();
 28.1054 +
 28.1055 +            // Output the integer portion.  Here 'count' is the total
 28.1056 +            // number of integer digits we will display, including both
 28.1057 +            // leading zeros required to satisfy getMinimumIntegerDigits,
 28.1058 +            // and actual digits present in the number.
 28.1059 +            int count = minIntDigits;
 28.1060 +            int digitIndex = 0; // Index into digitList.fDigits[]
 28.1061 +            if (digitList.decimalAt > 0 && count < digitList.decimalAt) {
 28.1062 +                count = digitList.decimalAt;
 28.1063 +            }
 28.1064 +
 28.1065 +            // Handle the case where getMaximumIntegerDigits() is smaller
 28.1066 +            // than the real number of integer digits.  If this is so, we
 28.1067 +            // output the least significant max integer digits.  For example,
 28.1068 +            // the value 1997 printed with 2 max integer digits is just "97".
 28.1069 +            if (count > maxIntDigits) {
 28.1070 +                count = maxIntDigits;
 28.1071 +                digitIndex = digitList.decimalAt - count;
 28.1072 +            }
 28.1073 +
 28.1074 +            int sizeBeforeIntegerPart = result.length();
 28.1075 +            for (int i=count-1; i>=0; --i) {
 28.1076 +                if (i < digitList.decimalAt && digitIndex < digitList.count) {
 28.1077 +                    // Output a real digit
 28.1078 +                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
 28.1079 +                } else {
 28.1080 +                    // Output a leading zero
 28.1081 +                    result.append(zero);
 28.1082 +                }
 28.1083 +
 28.1084 +                // Output grouping separator if necessary.  Don't output a
 28.1085 +                // grouping separator if i==0 though; that's at the end of
 28.1086 +                // the integer part.
 28.1087 +                if (isGroupingUsed() && i>0 && (groupingSize != 0) &&
 28.1088 +                    (i % groupingSize == 0)) {
 28.1089 +                    int gStart = result.length();
 28.1090 +                    result.append(grouping);
 28.1091 +                    delegate.formatted(Field.GROUPING_SEPARATOR,
 28.1092 +                                       Field.GROUPING_SEPARATOR, gStart,
 28.1093 +                                       result.length(), result);
 28.1094 +                }
 28.1095 +            }
 28.1096 +
 28.1097 +            // Determine whether or not there are any printable fractional
 28.1098 +            // digits.  If we've used up the digits we know there aren't.
 28.1099 +            boolean fractionPresent = (minFraDigits > 0) ||
 28.1100 +                (!isInteger && digitIndex < digitList.count);
 28.1101 +
 28.1102 +            // If there is no fraction present, and we haven't printed any
 28.1103 +            // integer digits, then print a zero.  Otherwise we won't print
 28.1104 +            // _any_ digits, and we won't be able to parse this string.
 28.1105 +            if (!fractionPresent && result.length() == sizeBeforeIntegerPart) {
 28.1106 +                result.append(zero);
 28.1107 +            }
 28.1108 +
 28.1109 +            delegate.formatted(INTEGER_FIELD, Field.INTEGER, Field.INTEGER,
 28.1110 +                               iFieldStart, result.length(), result);
 28.1111 +
 28.1112 +            // Output the decimal separator if we always do so.
 28.1113 +            int sStart = result.length();
 28.1114 +            if (decimalSeparatorAlwaysShown || fractionPresent) {
 28.1115 +                result.append(decimal);
 28.1116 +            }
 28.1117 +
 28.1118 +            if (sStart != result.length()) {
 28.1119 +                delegate.formatted(Field.DECIMAL_SEPARATOR,
 28.1120 +                                   Field.DECIMAL_SEPARATOR,
 28.1121 +                                   sStart, result.length(), result);
 28.1122 +            }
 28.1123 +            int fFieldStart = result.length();
 28.1124 +
 28.1125 +            for (int i=0; i < maxFraDigits; ++i) {
 28.1126 +                // Here is where we escape from the loop.  We escape if we've
 28.1127 +                // output the maximum fraction digits (specified in the for
 28.1128 +                // expression above).
 28.1129 +                // We also stop when we've output the minimum digits and either:
 28.1130 +                // we have an integer, so there is no fractional stuff to
 28.1131 +                // display, or we're out of significant digits.
 28.1132 +                if (i >= minFraDigits &&
 28.1133 +                    (isInteger || digitIndex >= digitList.count)) {
 28.1134 +                    break;
 28.1135 +                }
 28.1136 +
 28.1137 +                // Output leading fractional zeros. These are zeros that come
 28.1138 +                // after the decimal but before any significant digits. These
 28.1139 +                // are only output if abs(number being formatted) < 1.0.
 28.1140 +                if (-1-i > (digitList.decimalAt-1)) {
 28.1141 +                    result.append(zero);
 28.1142 +                    continue;
 28.1143 +                }
 28.1144 +
 28.1145 +                // Output a digit, if we have any precision left, or a
 28.1146 +                // zero if we don't.  We don't want to output noise digits.
 28.1147 +                if (!isInteger && digitIndex < digitList.count) {
 28.1148 +                    result.append((char)(digitList.digits[digitIndex++] + zeroDelta));
 28.1149 +                } else {
 28.1150 +                    result.append(zero);
 28.1151 +                }
 28.1152 +            }
 28.1153 +
 28.1154 +            // Record field information for caller.
 28.1155 +            delegate.formatted(FRACTION_FIELD, Field.FRACTION, Field.FRACTION,
 28.1156 +                               fFieldStart, result.length(), result);
 28.1157 +        }
 28.1158 +
 28.1159 +        if (isNegative) {
 28.1160 +            append(result, negativeSuffix, delegate,
 28.1161 +                   getNegativeSuffixFieldPositions(), Field.SIGN);
 28.1162 +        }
 28.1163 +        else {
 28.1164 +            append(result, positiveSuffix, delegate,
 28.1165 +                   getPositiveSuffixFieldPositions(), Field.SIGN);
 28.1166 +        }
 28.1167 +
 28.1168 +        return result;
 28.1169 +    }
 28.1170 +
 28.1171 +    /**
 28.1172 +     * Appends the String <code>string</code> to <code>result</code>.
 28.1173 +     * <code>delegate</code> is notified of all  the
 28.1174 +     * <code>FieldPosition</code>s in <code>positions</code>.
 28.1175 +     * <p>
 28.1176 +     * If one of the <code>FieldPosition</code>s in <code>positions</code>
 28.1177 +     * identifies a <code>SIGN</code> attribute, it is mapped to
 28.1178 +     * <code>signAttribute</code>. This is used
 28.1179 +     * to map the <code>SIGN</code> attribute to the <code>EXPONENT</code>
 28.1180 +     * attribute as necessary.
 28.1181 +     * <p>
 28.1182 +     * This is used by <code>subformat</code> to add the prefix/suffix.
 28.1183 +     */
 28.1184 +    private void append(StringBuffer result, String string,
 28.1185 +                        FieldDelegate delegate,
 28.1186 +                        FieldPosition[] positions,
 28.1187 +                        Format.Field signAttribute) {
 28.1188 +        int start = result.length();
 28.1189 +
 28.1190 +        if (string.length() > 0) {
 28.1191 +            result.append(string);
 28.1192 +            for (int counter = 0, max = positions.length; counter < max;
 28.1193 +                 counter++) {
 28.1194 +                FieldPosition fp = positions[counter];
 28.1195 +                Format.Field attribute = fp.getFieldAttribute();
 28.1196 +
 28.1197 +                if (attribute == Field.SIGN) {
 28.1198 +                    attribute = signAttribute;
 28.1199 +                }
 28.1200 +                delegate.formatted(attribute, attribute,
 28.1201 +                                   start + fp.getBeginIndex(),
 28.1202 +                                   start + fp.getEndIndex(), result);
 28.1203 +            }
 28.1204 +        }
 28.1205 +    }
 28.1206 +
 28.1207 +    /**
 28.1208 +     * Parses text from a string to produce a <code>Number</code>.
 28.1209 +     * <p>
 28.1210 +     * The method attempts to parse text starting at the index given by
 28.1211 +     * <code>pos</code>.
 28.1212 +     * If parsing succeeds, then the index of <code>pos</code> is updated
 28.1213 +     * to the index after the last character used (parsing does not necessarily
 28.1214 +     * use all characters up to the end of the string), and the parsed
 28.1215 +     * number is returned. The updated <code>pos</code> can be used to
 28.1216 +     * indicate the starting point for the next call to this method.
 28.1217 +     * If an error occurs, then the index of <code>pos</code> is not
 28.1218 +     * changed, the error index of <code>pos</code> is set to the index of
 28.1219 +     * the character where the error occurred, and null is returned.
 28.1220 +     * <p>
 28.1221 +     * The subclass returned depends on the value of {@link #isParseBigDecimal}
 28.1222 +     * as well as on the string being parsed.
 28.1223 +     * <ul>
 28.1224 +     *   <li>If <code>isParseBigDecimal()</code> is false (the default),
 28.1225 +     *       most integer values are returned as <code>Long</code>
 28.1226 +     *       objects, no matter how they are written: <code>"17"</code> and
 28.1227 +     *       <code>"17.000"</code> both parse to <code>Long(17)</code>.
 28.1228 +     *       Values that cannot fit into a <code>Long</code> are returned as
 28.1229 +     *       <code>Double</code>s. This includes values with a fractional part,
 28.1230 +     *       infinite values, <code>NaN</code>, and the value -0.0.
 28.1231 +     *       <code>DecimalFormat</code> does <em>not</em> decide whether to
 28.1232 +     *       return a <code>Double</code> or a <code>Long</code> based on the
 28.1233 +     *       presence of a decimal separator in the source string. Doing so
 28.1234 +     *       would prevent integers that overflow the mantissa of a double,
 28.1235 +     *       such as <code>"-9,223,372,036,854,775,808.00"</code>, from being
 28.1236 +     *       parsed accurately.
 28.1237 +     *       <p>
 28.1238 +     *       Callers may use the <code>Number</code> methods
 28.1239 +     *       <code>doubleValue</code>, <code>longValue</code>, etc., to obtain
 28.1240 +     *       the type they want.
 28.1241 +     *   <li>If <code>isParseBigDecimal()</code> is true, values are returned
 28.1242 +     *       as <code>BigDecimal</code> objects. The values are the ones
 28.1243 +     *       constructed by {@link java.math.BigDecimal#BigDecimal(String)}
 28.1244 +     *       for corresponding strings in locale-independent format. The
 28.1245 +     *       special cases negative and positive infinity and NaN are returned
 28.1246 +     *       as <code>Double</code> instances holding the values of the
 28.1247 +     *       corresponding <code>Double</code> constants.
 28.1248 +     * </ul>
 28.1249 +     * <p>
 28.1250 +     * <code>DecimalFormat</code> parses all Unicode characters that represent
 28.1251 +     * decimal digits, as defined by <code>Character.digit()</code>. In
 28.1252 +     * addition, <code>DecimalFormat</code> also recognizes as digits the ten
 28.1253 +     * consecutive characters starting with the localized zero digit defined in
 28.1254 +     * the <code>DecimalFormatSymbols</code> object.
 28.1255 +     *
 28.1256 +     * @param text the string to be parsed
 28.1257 +     * @param pos  A <code>ParsePosition</code> object with index and error
 28.1258 +     *             index information as described above.
 28.1259 +     * @return     the parsed value, or <code>null</code> if the parse fails
 28.1260 +     * @exception  NullPointerException if <code>text</code> or
 28.1261 +     *             <code>pos</code> is null.
 28.1262 +     */
 28.1263 +    public Number parse(String text, ParsePosition pos) {
 28.1264 +        // special case NaN
 28.1265 +        if (text.regionMatches(pos.index, symbols.getNaN(), 0, symbols.getNaN().length())) {
 28.1266 +            pos.index = pos.index + symbols.getNaN().length();
 28.1267 +            return new Double(Double.NaN);
 28.1268 +        }
 28.1269 +
 28.1270 +        boolean[] status = new boolean[STATUS_LENGTH];
 28.1271 +        if (!subparse(text, pos, positivePrefix, negativePrefix, digitList, false, status)) {
 28.1272 +            return null;
 28.1273 +        }
 28.1274 +
 28.1275 +        // special case INFINITY
 28.1276 +        if (status[STATUS_INFINITE]) {
 28.1277 +            if (status[STATUS_POSITIVE] == (multiplier >= 0)) {
 28.1278 +                return new Double(Double.POSITIVE_INFINITY);
 28.1279 +            } else {
 28.1280 +                return new Double(Double.NEGATIVE_INFINITY);
 28.1281 +            }
 28.1282 +        }
 28.1283 +
 28.1284 +        if (multiplier == 0) {
 28.1285 +            if (digitList.isZero()) {
 28.1286 +                return new Double(Double.NaN);
 28.1287 +            } else if (status[STATUS_POSITIVE]) {
 28.1288 +                return new Double(Double.POSITIVE_INFINITY);
 28.1289 +            } else {
 28.1290 +                return new Double(Double.NEGATIVE_INFINITY);
 28.1291 +            }
 28.1292 +        }
 28.1293 +
 28.1294 +        if (isParseBigDecimal()) {
 28.1295 +            BigDecimal bigDecimalResult = digitList.getBigDecimal();
 28.1296 +
 28.1297 +            if (multiplier != 1) {
 28.1298 +                try {
 28.1299 +                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier());
 28.1300 +                }
 28.1301 +                catch (ArithmeticException e) {  // non-terminating decimal expansion
 28.1302 +                    bigDecimalResult = bigDecimalResult.divide(getBigDecimalMultiplier(), roundingMode);
 28.1303 +                }
 28.1304 +            }
 28.1305 +
 28.1306 +            if (!status[STATUS_POSITIVE]) {
 28.1307 +                bigDecimalResult = bigDecimalResult.negate();
 28.1308 +            }
 28.1309 +            return bigDecimalResult;
 28.1310 +        } else {
 28.1311 +            boolean gotDouble = true;
 28.1312 +            boolean gotLongMinimum = false;
 28.1313 +            double  doubleResult = 0.0;
 28.1314 +            long    longResult = 0;
 28.1315 +
 28.1316 +            // Finally, have DigitList parse the digits into a value.
 28.1317 +            if (digitList.fitsIntoLong(status[STATUS_POSITIVE], isParseIntegerOnly())) {
 28.1318 +                gotDouble = false;
 28.1319 +                longResult = digitList.getLong();
 28.1320 +                if (longResult < 0) {  // got Long.MIN_VALUE
 28.1321 +                    gotLongMinimum = true;
 28.1322 +                }
 28.1323 +            } else {
 28.1324 +                doubleResult = digitList.getDouble();
 28.1325 +            }
 28.1326 +
 28.1327 +            // Divide by multiplier. We have to be careful here not to do
 28.1328 +            // unneeded conversions between double and long.
 28.1329 +            if (multiplier != 1) {
 28.1330 +                if (gotDouble) {
 28.1331 +                    doubleResult /= multiplier;
 28.1332 +                } else {
 28.1333 +                    // Avoid converting to double if we can
 28.1334 +                    if (longResult % multiplier == 0) {
 28.1335 +                        longResult /= multiplier;
 28.1336 +                    } else {
 28.1337 +                        doubleResult = ((double)longResult) / multiplier;
 28.1338 +                        gotDouble = true;
 28.1339 +                    }
 28.1340 +                }
 28.1341 +            }
 28.1342 +
 28.1343 +            if (!status[STATUS_POSITIVE] && !gotLongMinimum) {
 28.1344 +                doubleResult = -doubleResult;
 28.1345 +                longResult = -longResult;
 28.1346 +            }
 28.1347 +
 28.1348 +            // At this point, if we divided the result by the multiplier, the
 28.1349 +            // result may fit into a long.  We check for this case and return
 28.1350 +            // a long if possible.
 28.1351 +            // We must do this AFTER applying the negative (if appropriate)
 28.1352 +            // in order to handle the case of LONG_MIN; otherwise, if we do
 28.1353 +            // this with a positive value -LONG_MIN, the double is > 0, but
 28.1354 +            // the long is < 0. We also must retain a double in the case of
 28.1355 +            // -0.0, which will compare as == to a long 0 cast to a double
 28.1356 +            // (bug 4162852).
 28.1357 +            if (multiplier != 1 && gotDouble) {
 28.1358 +                longResult = (long)doubleResult;
 28.1359 +                gotDouble = ((doubleResult != (double)longResult) ||
 28.1360 +                            (doubleResult == 0.0 && 1/doubleResult < 0.0)) &&
 28.1361 +                            !isParseIntegerOnly();
 28.1362 +            }
 28.1363 +
 28.1364 +            return gotDouble ?
 28.1365 +                (Number)new Double(doubleResult) : (Number)new Long(longResult);
 28.1366 +        }
 28.1367 +    }
 28.1368 +
 28.1369 +    /**
 28.1370 +     * Return a BigInteger multiplier.
 28.1371 +     */
 28.1372 +    private BigInteger getBigIntegerMultiplier() {
 28.1373 +        if (bigIntegerMultiplier == null) {
 28.1374 +            bigIntegerMultiplier = BigInteger.valueOf(multiplier);
 28.1375 +        }
 28.1376 +        return bigIntegerMultiplier;
 28.1377 +    }
 28.1378 +    private transient BigInteger bigIntegerMultiplier;
 28.1379 +
 28.1380 +    /**
 28.1381 +     * Return a BigDecimal multiplier.
 28.1382 +     */
 28.1383 +    private BigDecimal getBigDecimalMultiplier() {
 28.1384 +        if (bigDecimalMultiplier == null) {
 28.1385 +            bigDecimalMultiplier = new BigDecimal(multiplier);
 28.1386 +        }
 28.1387 +        return bigDecimalMultiplier;
 28.1388 +    }
 28.1389 +    private transient BigDecimal bigDecimalMultiplier;
 28.1390 +
 28.1391 +    private static final int STATUS_INFINITE = 0;
 28.1392 +    private static final int STATUS_POSITIVE = 1;
 28.1393 +    private static final int STATUS_LENGTH   = 2;
 28.1394 +
 28.1395 +    /**
 28.1396 +     * Parse the given text into a number.  The text is parsed beginning at
 28.1397 +     * parsePosition, until an unparseable character is seen.
 28.1398 +     * @param text The string to parse.
 28.1399 +     * @param parsePosition The position at which to being parsing.  Upon
 28.1400 +     * return, the first unparseable character.
 28.1401 +     * @param digits The DigitList to set to the parsed value.
 28.1402 +     * @param isExponent If true, parse an exponent.  This means no
 28.1403 +     * infinite values and integer only.
 28.1404 +     * @param status Upon return contains boolean status flags indicating
 28.1405 +     * whether the value was infinite and whether it was positive.
 28.1406 +     */
 28.1407 +    private final boolean subparse(String text, ParsePosition parsePosition,
 28.1408 +                   String positivePrefix, String negativePrefix,
 28.1409 +                   DigitList digits, boolean isExponent,
 28.1410 +                   boolean status[]) {
 28.1411 +        int position = parsePosition.index;
 28.1412 +        int oldStart = parsePosition.index;
 28.1413 +        int backup;
 28.1414 +        boolean gotPositive, gotNegative;
 28.1415 +
 28.1416 +        // check for positivePrefix; take longest
 28.1417 +        gotPositive = text.regionMatches(position, positivePrefix, 0,
 28.1418 +                                         positivePrefix.length());
 28.1419 +        gotNegative = text.regionMatches(position, negativePrefix, 0,
 28.1420 +                                         negativePrefix.length());
 28.1421 +
 28.1422 +        if (gotPositive && gotNegative) {
 28.1423 +            if (positivePrefix.length() > negativePrefix.length()) {
 28.1424 +                gotNegative = false;
 28.1425 +            } else if (positivePrefix.length() < negativePrefix.length()) {
 28.1426 +                gotPositive = false;
 28.1427 +            }
 28.1428 +        }
 28.1429 +
 28.1430 +        if (gotPositive) {
 28.1431 +            position += positivePrefix.length();
 28.1432 +        } else if (gotNegative) {
 28.1433 +            position += negativePrefix.length();
 28.1434 +        } else {
 28.1435 +            parsePosition.errorIndex = position;
 28.1436 +            return false;
 28.1437 +        }
 28.1438 +
 28.1439 +        // process digits or Inf, find decimal position
 28.1440 +        status[STATUS_INFINITE] = false;
 28.1441 +        if (!isExponent && text.regionMatches(position,symbols.getInfinity(),0,
 28.1442 +                          symbols.getInfinity().length())) {
 28.1443 +            position += symbols.getInfinity().length();
 28.1444 +            status[STATUS_INFINITE] = true;
 28.1445 +        } else {
 28.1446 +            // We now have a string of digits, possibly with grouping symbols,
 28.1447 +            // and decimal points.  We want to process these into a DigitList.
 28.1448 +            // We don't want to put a bunch of leading zeros into the DigitList
 28.1449 +            // though, so we keep track of the location of the decimal point,
 28.1450 +            // put only significant digits into the DigitList, and adjust the
 28.1451 +            // exponent as needed.
 28.1452 +
 28.1453 +            digits.decimalAt = digits.count = 0;
 28.1454 +            char zero = symbols.getZeroDigit();
 28.1455 +            char decimal = isCurrencyFormat ?
 28.1456 +                symbols.getMonetaryDecimalSeparator() :
 28.1457 +                symbols.getDecimalSeparator();
 28.1458 +            char grouping = symbols.getGroupingSeparator();
 28.1459 +            String exponentString = symbols.getExponentSeparator();
 28.1460 +            boolean sawDecimal = false;
 28.1461 +            boolean sawExponent = false;
 28.1462 +            boolean sawDigit = false;
 28.1463 +            int exponent = 0; // Set to the exponent value, if any
 28.1464 +
 28.1465 +            // We have to track digitCount ourselves, because digits.count will
 28.1466 +            // pin when the maximum allowable digits is reached.
 28.1467 +            int digitCount = 0;
 28.1468 +
 28.1469 +            backup = -1;
 28.1470 +            for (; position < text.length(); ++position) {
 28.1471 +                char ch = text.charAt(position);
 28.1472 +
 28.1473 +                /* We recognize all digit ranges, not only the Latin digit range
 28.1474 +                 * '0'..'9'.  We do so by using the Character.digit() method,
 28.1475 +                 * which converts a valid Unicode digit to the range 0..9.
 28.1476 +                 *
 28.1477 +                 * The character 'ch' may be a digit.  If so, place its value
 28.1478 +                 * from 0 to 9 in 'digit'.  First try using the locale digit,
 28.1479 +                 * which may or MAY NOT be a standard Unicode digit range.  If
 28.1480 +                 * this fails, try using the standard Unicode digit ranges by
 28.1481 +                 * calling Character.digit().  If this also fails, digit will
 28.1482 +                 * have a value outside the range 0..9.
 28.1483 +                 */
 28.1484 +                int digit = ch - zero;
 28.1485 +                if (digit < 0 || digit > 9) {
 28.1486 +                    digit = Character.digit(ch, 10);
 28.1487 +                }
 28.1488 +
 28.1489 +                if (digit == 0) {
 28.1490 +                    // Cancel out backup setting (see grouping handler below)
 28.1491 +                    backup = -1; // Do this BEFORE continue statement below!!!
 28.1492 +                    sawDigit = true;
 28.1493 +
 28.1494 +                    // Handle leading zeros
 28.1495 +                    if (digits.count == 0) {
 28.1496 +                        // Ignore leading zeros in integer part of number.
 28.1497 +                        if (!sawDecimal) {
 28.1498 +                            continue;
 28.1499 +                        }
 28.1500 +
 28.1501 +                        // If we have seen the decimal, but no significant
 28.1502 +                        // digits yet, then we account for leading zeros by
 28.1503 +                        // decrementing the digits.decimalAt into negative
 28.1504 +                        // values.
 28.1505 +                        --digits.decimalAt;
 28.1506 +                    } else {
 28.1507 +                        ++digitCount;
 28.1508 +                        digits.append((char)(digit + '0'));
 28.1509 +                    }
 28.1510 +                } else if (digit > 0 && digit <= 9) { // [sic] digit==0 handled above
 28.1511 +                    sawDigit = true;
 28.1512 +                    ++digitCount;
 28.1513 +                    digits.append((char)(digit + '0'));
 28.1514 +
 28.1515 +                    // Cancel out backup setting (see grouping handler below)
 28.1516 +                    backup = -1;
 28.1517 +                } else if (!isExponent && ch == decimal) {
 28.1518 +                    // If we're only parsing integers, or if we ALREADY saw the
 28.1519 +                    // decimal, then don't parse this one.
 28.1520 +                    if (isParseIntegerOnly() || sawDecimal) {
 28.1521 +                        break;
 28.1522 +                    }
 28.1523 +                    digits.decimalAt = digitCount; // Not digits.count!
 28.1524 +                    sawDecimal = true;
 28.1525 +                } else if (!isExponent && ch == grouping && isGroupingUsed()) {
 28.1526 +                    if (sawDecimal) {
 28.1527 +                        break;
 28.1528 +                    }
 28.1529 +                    // Ignore grouping characters, if we are using them, but
 28.1530 +                    // require that they be followed by a digit.  Otherwise
 28.1531 +                    // we backup and reprocess them.
 28.1532 +                    backup = position;
 28.1533 +                } else if (!isExponent && text.regionMatches(position, exponentString, 0, exponentString.length())
 28.1534 +                             && !sawExponent) {
 28.1535 +                    // Process the exponent by recursively calling this method.
 28.1536 +                     ParsePosition pos = new ParsePosition(position + exponentString.length());
 28.1537 +                    boolean[] stat = new boolean[STATUS_LENGTH];
 28.1538 +                    DigitList exponentDigits = new DigitList();
 28.1539 +
 28.1540 +                    if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
 28.1541 +                        exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
 28.1542 +                        position = pos.index; // Advance past the exponent
 28.1543 +                        exponent = (int)exponentDigits.getLong();
 28.1544 +                        if (!stat[STATUS_POSITIVE]) {
 28.1545 +                            exponent = -exponent;
 28.1546 +                        }
 28.1547 +                        sawExponent = true;
 28.1548 +                    }
 28.1549 +                    break; // Whether we fail or succeed, we exit this loop
 28.1550 +                }
 28.1551 +                else {
 28.1552 +                    break;
 28.1553 +                }
 28.1554 +            }
 28.1555 +
 28.1556 +            if (backup != -1) {
 28.1557 +                position = backup;
 28.1558 +            }
 28.1559 +
 28.1560 +            // If there was no decimal point we have an integer
 28.1561 +            if (!sawDecimal) {
 28.1562 +                digits.decimalAt = digitCount; // Not digits.count!
 28.1563 +            }
 28.1564 +
 28.1565 +            // Adjust for exponent, if any
 28.1566 +            digits.decimalAt += exponent;
 28.1567 +
 28.1568 +            // If none of the text string was recognized.  For example, parse
 28.1569 +            // "x" with pattern "#0.00" (return index and error index both 0)
 28.1570 +            // parse "$" with pattern "$#0.00". (return index 0 and error
 28.1571 +            // index 1).
 28.1572 +            if (!sawDigit && digitCount == 0) {
 28.1573 +                parsePosition.index = oldStart;
 28.1574 +                parsePosition.errorIndex = oldStart;
 28.1575 +                return false;
 28.1576 +            }
 28.1577 +        }
 28.1578 +
 28.1579 +        // check for suffix
 28.1580 +        if (!isExponent) {
 28.1581 +            if (gotPositive) {
 28.1582 +                gotPositive = text.regionMatches(position,positiveSuffix,0,
 28.1583 +                                                 positiveSuffix.length());
 28.1584 +            }
 28.1585 +            if (gotNegative) {
 28.1586 +                gotNegative = text.regionMatches(position,negativeSuffix,0,
 28.1587 +                                                 negativeSuffix.length());
 28.1588 +            }
 28.1589 +
 28.1590 +        // if both match, take longest
 28.1591 +        if (gotPositive && gotNegative) {
 28.1592 +            if (positiveSuffix.length() > negativeSuffix.length()) {
 28.1593 +                gotNegative = false;
 28.1594 +            } else if (positiveSuffix.length() < negativeSuffix.length()) {
 28.1595 +                gotPositive = false;
 28.1596 +            }
 28.1597 +        }
 28.1598 +
 28.1599 +        // fail if neither or both
 28.1600 +        if (gotPositive == gotNegative) {
 28.1601 +            parsePosition.errorIndex = position;
 28.1602 +            return false;
 28.1603 +        }
 28.1604 +
 28.1605 +        parsePosition.index = position +
 28.1606 +            (gotPositive ? positiveSuffix.length() : negativeSuffix.length()); // mark success!
 28.1607 +        } else {
 28.1608 +            parsePosition.index = position;
 28.1609 +        }
 28.1610 +
 28.1611 +        status[STATUS_POSITIVE] = gotPositive;
 28.1612 +        if (parsePosition.index == oldStart) {
 28.1613 +            parsePosition.errorIndex = position;
 28.1614 +            return false;
 28.1615 +        }
 28.1616 +        return true;
 28.1617 +    }
 28.1618 +
 28.1619 +    /**
 28.1620 +     * Returns a copy of the decimal format symbols, which is generally not
 28.1621 +     * changed by the programmer or user.
 28.1622 +     * @return a copy of the desired DecimalFormatSymbols
 28.1623 +     * @see java.text.DecimalFormatSymbols
 28.1624 +     */
 28.1625 +    public DecimalFormatSymbols getDecimalFormatSymbols() {
 28.1626 +        try {
 28.1627 +            // don't allow multiple references
 28.1628 +            return (DecimalFormatSymbols) symbols.clone();
 28.1629 +        } catch (Exception foo) {
 28.1630 +            return null; // should never happen
 28.1631 +        }
 28.1632 +    }
 28.1633 +
 28.1634 +
 28.1635 +    /**
 28.1636 +     * Sets the decimal format symbols, which is generally not changed
 28.1637 +     * by the programmer or user.
 28.1638 +     * @param newSymbols desired DecimalFormatSymbols
 28.1639 +     * @see java.text.DecimalFormatSymbols
 28.1640 +     */
 28.1641 +    public void setDecimalFormatSymbols(DecimalFormatSymbols newSymbols) {
 28.1642 +        try {
 28.1643 +            // don't allow multiple references
 28.1644 +            symbols = (DecimalFormatSymbols) newSymbols.clone();
 28.1645 +            expandAffixes();
 28.1646 +        } catch (Exception foo) {
 28.1647 +            // should never happen
 28.1648 +        }
 28.1649 +    }
 28.1650 +
 28.1651 +    /**
 28.1652 +     * Get the positive prefix.
 28.1653 +     * <P>Examples: +123, $123, sFr123
 28.1654 +     */
 28.1655 +    public String getPositivePrefix () {
 28.1656 +        return positivePrefix;
 28.1657 +    }
 28.1658 +
 28.1659 +    /**
 28.1660 +     * Set the positive prefix.
 28.1661 +     * <P>Examples: +123, $123, sFr123
 28.1662 +     */
 28.1663 +    public void setPositivePrefix (String newValue) {
 28.1664 +        positivePrefix = newValue;
 28.1665 +        posPrefixPattern = null;
 28.1666 +        positivePrefixFieldPositions = null;
 28.1667 +    }
 28.1668 +
 28.1669 +    /**
 28.1670 +     * Returns the FieldPositions of the fields in the prefix used for
 28.1671 +     * positive numbers. This is not used if the user has explicitly set
 28.1672 +     * a positive prefix via <code>setPositivePrefix</code>. This is
 28.1673 +     * lazily created.
 28.1674 +     *
 28.1675 +     * @return FieldPositions in positive prefix
 28.1676 +     */
 28.1677 +    private FieldPosition[] getPositivePrefixFieldPositions() {
 28.1678 +        if (positivePrefixFieldPositions == null) {
 28.1679 +            if (posPrefixPattern != null) {
 28.1680 +                positivePrefixFieldPositions = expandAffix(posPrefixPattern);
 28.1681 +            }
 28.1682 +            else {
 28.1683 +                positivePrefixFieldPositions = EmptyFieldPositionArray;
 28.1684 +            }
 28.1685 +        }
 28.1686 +        return positivePrefixFieldPositions;
 28.1687 +    }
 28.1688 +
 28.1689 +    /**
 28.1690 +     * Get the negative prefix.
 28.1691 +     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
 28.1692 +     */
 28.1693 +    public String getNegativePrefix () {
 28.1694 +        return negativePrefix;
 28.1695 +    }
 28.1696 +
 28.1697 +    /**
 28.1698 +     * Set the negative prefix.
 28.1699 +     * <P>Examples: -123, ($123) (with negative suffix), sFr-123
 28.1700 +     */
 28.1701 +    public void setNegativePrefix (String newValue) {
 28.1702 +        negativePrefix = newValue;
 28.1703 +        negPrefixPattern = null;
 28.1704 +    }
 28.1705 +
 28.1706 +    /**
 28.1707 +     * Returns the FieldPositions of the fields in the prefix used for
 28.1708 +     * negative numbers. This is not used if the user has explicitly set
 28.1709 +     * a negative prefix via <code>setNegativePrefix</code>. This is
 28.1710 +     * lazily created.
 28.1711 +     *
 28.1712 +     * @return FieldPositions in positive prefix
 28.1713 +     */
 28.1714 +    private FieldPosition[] getNegativePrefixFieldPositions() {
 28.1715 +        if (negativePrefixFieldPositions == null) {
 28.1716 +            if (negPrefixPattern != null) {
 28.1717 +                negativePrefixFieldPositions = expandAffix(negPrefixPattern);
 28.1718 +            }
 28.1719 +            else {
 28.1720 +                negativePrefixFieldPositions = EmptyFieldPositionArray;
 28.1721 +            }
 28.1722 +        }
 28.1723 +        return negativePrefixFieldPositions;
 28.1724 +    }
 28.1725 +
 28.1726 +    /**
 28.1727 +     * Get the positive suffix.
 28.1728 +     * <P>Example: 123%
 28.1729 +     */
 28.1730 +    public String getPositiveSuffix () {
 28.1731 +        return positiveSuffix;
 28.1732 +    }
 28.1733 +
 28.1734 +    /**
 28.1735 +     * Set the positive suffix.
 28.1736 +     * <P>Example: 123%
 28.1737 +     */
 28.1738 +    public void setPositiveSuffix (String newValue) {
 28.1739 +        positiveSuffix = newValue;
 28.1740 +        posSuffixPattern = null;
 28.1741 +    }
 28.1742 +
 28.1743 +    /**
 28.1744 +     * Returns the FieldPositions of the fields in the suffix used for
 28.1745 +     * positive numbers. This is not used if the user has explicitly set
 28.1746 +     * a positive suffix via <code>setPositiveSuffix</code>. This is
 28.1747 +     * lazily created.
 28.1748 +     *
 28.1749 +     * @return FieldPositions in positive prefix
 28.1750 +     */
 28.1751 +    private FieldPosition[] getPositiveSuffixFieldPositions() {
 28.1752 +        if (positiveSuffixFieldPositions == null) {
 28.1753 +            if (posSuffixPattern != null) {
 28.1754 +                positiveSuffixFieldPositions = expandAffix(posSuffixPattern);
 28.1755 +            }
 28.1756 +            else {
 28.1757 +                positiveSuffixFieldPositions = EmptyFieldPositionArray;
 28.1758 +            }
 28.1759 +        }
 28.1760 +        return positiveSuffixFieldPositions;
 28.1761 +    }
 28.1762 +
 28.1763 +    /**
 28.1764 +     * Get the negative suffix.
 28.1765 +     * <P>Examples: -123%, ($123) (with positive suffixes)
 28.1766 +     */
 28.1767 +    public String getNegativeSuffix () {
 28.1768 +        return negativeSuffix;
 28.1769 +    }
 28.1770 +
 28.1771 +    /**
 28.1772 +     * Set the negative suffix.
 28.1773 +     * <P>Examples: 123%
 28.1774 +     */
 28.1775 +    public void setNegativeSuffix (String newValue) {
 28.1776 +        negativeSuffix = newValue;
 28.1777 +        negSuffixPattern = null;
 28.1778 +    }
 28.1779 +
 28.1780 +    /**
 28.1781 +     * Returns the FieldPositions of the fields in the suffix used for
 28.1782 +     * negative numbers. This is not used if the user has explicitly set
 28.1783 +     * a negative suffix via <code>setNegativeSuffix</code>. This is
 28.1784 +     * lazily created.
 28.1785 +     *
 28.1786 +     * @return FieldPositions in positive prefix
 28.1787 +     */
 28.1788 +    private FieldPosition[] getNegativeSuffixFieldPositions() {
 28.1789 +        if (negativeSuffixFieldPositions == null) {
 28.1790 +            if (negSuffixPattern != null) {
 28.1791 +                negativeSuffixFieldPositions = expandAffix(negSuffixPattern);
 28.1792 +            }
 28.1793 +            else {
 28.1794 +                negativeSuffixFieldPositions = EmptyFieldPositionArray;
 28.1795 +            }
 28.1796 +        }
 28.1797 +        return negativeSuffixFieldPositions;
 28.1798 +    }
 28.1799 +
 28.1800 +    /**
 28.1801 +     * Gets the multiplier for use in percent, per mille, and similar
 28.1802 +     * formats.
 28.1803 +     *
 28.1804 +     * @see #setMultiplier(int)
 28.1805 +     */
 28.1806 +    public int getMultiplier () {
 28.1807 +        return multiplier;
 28.1808 +    }
 28.1809 +
 28.1810 +    /**
 28.1811 +     * Sets the multiplier for use in percent, per mille, and similar
 28.1812 +     * formats.
 28.1813 +     * For a percent format, set the multiplier to 100 and the suffixes to
 28.1814 +     * have '%' (for Arabic, use the Arabic percent sign).
 28.1815 +     * For a per mille format, set the multiplier to 1000 and the suffixes to
 28.1816 +     * have '&#92;u2030'.
 28.1817 +     *
 28.1818 +     * <P>Example: with multiplier 100, 1.23 is formatted as "123", and
 28.1819 +     * "123" is parsed into 1.23.
 28.1820 +     *
 28.1821 +     * @see #getMultiplier
 28.1822 +     */
 28.1823 +    public void setMultiplier (int newValue) {
 28.1824 +        multiplier = newValue;
 28.1825 +        bigDecimalMultiplier = null;
 28.1826 +        bigIntegerMultiplier = null;
 28.1827 +    }
 28.1828 +
 28.1829 +    /**
 28.1830 +     * Return the grouping size. Grouping size is the number of digits between
 28.1831 +     * grouping separators in the integer portion of a number.  For example,
 28.1832 +     * in the number "123,456.78", the grouping size is 3.
 28.1833 +     * @see #setGroupingSize
 28.1834 +     * @see java.text.NumberFormat#isGroupingUsed
 28.1835 +     * @see java.text.DecimalFormatSymbols#getGroupingSeparator
 28.1836 +     */
 28.1837 +    public int getGroupingSize () {
 28.1838 +        return groupingSize;
 28.1839 +    }
 28.1840 +
 28.1841 +    /**
 28.1842 +     * Set the grouping size. Grouping size is the number of digits between
 28.1843 +     * grouping separators in the integer portion of a number.  For example,
 28.1844 +     * in the number "123,456.78", the grouping size is 3.
 28.1845 +     * <br>
 28.1846 +     * The value passed in is converted to a byte, which may lose information.
 28.1847 +     * @see #getGroupingSize
 28.1848 +     * @see java.text.NumberFormat#setGroupingUsed
 28.1849 +     * @see java.text.DecimalFormatSymbols#setGroupingSeparator
 28.1850 +     */
 28.1851 +    public void setGroupingSize (int newValue) {
 28.1852 +        groupingSize = (byte)newValue;
 28.1853 +    }
 28.1854 +
 28.1855 +    /**
 28.1856 +     * Allows you to get the behavior of the decimal separator with integers.
 28.1857 +     * (The decimal separator will always appear with decimals.)
 28.1858 +     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
 28.1859 +     */
 28.1860 +    public boolean isDecimalSeparatorAlwaysShown() {
 28.1861 +        return decimalSeparatorAlwaysShown;
 28.1862 +    }
 28.1863 +
 28.1864 +    /**
 28.1865 +     * Allows you to set the behavior of the decimal separator with integers.
 28.1866 +     * (The decimal separator will always appear with decimals.)
 28.1867 +     * <P>Example: Decimal ON: 12345 -> 12345.; OFF: 12345 -> 12345
 28.1868 +     */
 28.1869 +    public void setDecimalSeparatorAlwaysShown(boolean newValue) {
 28.1870 +        decimalSeparatorAlwaysShown = newValue;
 28.1871 +    }
 28.1872 +
 28.1873 +    /**
 28.1874 +     * Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
 28.1875 +     * method returns <code>BigDecimal</code>. The default value is false.
 28.1876 +     * @see #setParseBigDecimal
 28.1877 +     * @since 1.5
 28.1878 +     */
 28.1879 +    public boolean isParseBigDecimal() {
 28.1880 +        return parseBigDecimal;
 28.1881 +    }
 28.1882 +
 28.1883 +    /**
 28.1884 +     * Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
 28.1885 +     * method returns <code>BigDecimal</code>.
 28.1886 +     * @see #isParseBigDecimal
 28.1887 +     * @since 1.5
 28.1888 +     */
 28.1889 +    public void setParseBigDecimal(boolean newValue) {
 28.1890 +        parseBigDecimal = newValue;
 28.1891 +    }
 28.1892 +
 28.1893 +    /**
 28.1894 +     * Standard override; no change in semantics.
 28.1895 +     */
 28.1896 +    public Object clone() {
 28.1897 +        try {
 28.1898 +            DecimalFormat other = (DecimalFormat) super.clone();
 28.1899 +            other.symbols = (DecimalFormatSymbols) symbols.clone();
 28.1900 +            other.digitList = (DigitList) digitList.clone();
 28.1901 +            return other;
 28.1902 +        } catch (Exception e) {
 28.1903 +            throw new InternalError();
 28.1904 +        }
 28.1905 +    }
 28.1906 +
 28.1907 +    /**
 28.1908 +     * Overrides equals
 28.1909 +     */
 28.1910 +    public boolean equals(Object obj)
 28.1911 +    {
 28.1912 +        if (obj == null) return false;
 28.1913 +        if (!super.equals(obj)) return false; // super does class check
 28.1914 +        DecimalFormat other = (DecimalFormat) obj;
 28.1915 +        return ((posPrefixPattern == other.posPrefixPattern &&
 28.1916 +                 positivePrefix.equals(other.positivePrefix))
 28.1917 +                || (posPrefixPattern != null &&
 28.1918 +                    posPrefixPattern.equals(other.posPrefixPattern)))
 28.1919 +            && ((posSuffixPattern == other.posSuffixPattern &&
 28.1920 +                 positiveSuffix.equals(other.positiveSuffix))
 28.1921 +                || (posSuffixPattern != null &&
 28.1922 +                    posSuffixPattern.equals(other.posSuffixPattern)))
 28.1923 +            && ((negPrefixPattern == other.negPrefixPattern &&
 28.1924 +                 negativePrefix.equals(other.negativePrefix))
 28.1925 +                || (negPrefixPattern != null &&
 28.1926 +                    negPrefixPattern.equals(other.negPrefixPattern)))
 28.1927 +            && ((negSuffixPattern == other.negSuffixPattern &&
 28.1928 +                 negativeSuffix.equals(other.negativeSuffix))
 28.1929 +                || (negSuffixPattern != null &&
 28.1930 +                    negSuffixPattern.equals(other.negSuffixPattern)))
 28.1931 +            && multiplier == other.multiplier
 28.1932 +            && groupingSize == other.groupingSize
 28.1933 +            && decimalSeparatorAlwaysShown == other.decimalSeparatorAlwaysShown
 28.1934 +            && parseBigDecimal == other.parseBigDecimal
 28.1935 +            && useExponentialNotation == other.useExponentialNotation
 28.1936 +            && (!useExponentialNotation ||
 28.1937 +                minExponentDigits == other.minExponentDigits)
 28.1938 +            && maximumIntegerDigits == other.maximumIntegerDigits
 28.1939 +            && minimumIntegerDigits == other.minimumIntegerDigits
 28.1940 +            && maximumFractionDigits == other.maximumFractionDigits
 28.1941 +            && minimumFractionDigits == other.minimumFractionDigits
 28.1942 +            && roundingMode == other.roundingMode
 28.1943 +            && symbols.equals(other.symbols);
 28.1944 +    }
 28.1945 +
 28.1946 +    /**
 28.1947 +     * Overrides hashCode
 28.1948 +     */
 28.1949 +    public int hashCode() {
 28.1950 +        return super.hashCode() * 37 + positivePrefix.hashCode();
 28.1951 +        // just enough fields for a reasonable distribution
 28.1952 +    }
 28.1953 +
 28.1954 +    /**
 28.1955 +     * Synthesizes a pattern string that represents the current state
 28.1956 +     * of this Format object.
 28.1957 +     * @see #applyPattern
 28.1958 +     */
 28.1959 +    public String toPattern() {
 28.1960 +        return toPattern( false );
 28.1961 +    }
 28.1962 +
 28.1963 +    /**
 28.1964 +     * Synthesizes a localized pattern string that represents the current
 28.1965 +     * state of this Format object.
 28.1966 +     * @see #applyPattern
 28.1967 +     */
 28.1968 +    public String toLocalizedPattern() {
 28.1969 +        return toPattern( true );
 28.1970 +    }
 28.1971 +
 28.1972 +    /**
 28.1973 +     * Expand the affix pattern strings into the expanded affix strings.  If any
 28.1974 +     * affix pattern string is null, do not expand it.  This method should be
 28.1975 +     * called any time the symbols or the affix patterns change in order to keep
 28.1976 +     * the expanded affix strings up to date.
 28.1977 +     */
 28.1978 +    private void expandAffixes() {
 28.1979 +        // Reuse one StringBuffer for better performance
 28.1980 +        StringBuffer buffer = new StringBuffer();
 28.1981 +        if (posPrefixPattern != null) {
 28.1982 +            positivePrefix = expandAffix(posPrefixPattern, buffer);
 28.1983 +            positivePrefixFieldPositions = null;
 28.1984 +        }
 28.1985 +        if (posSuffixPattern != null) {
 28.1986 +            positiveSuffix = expandAffix(posSuffixPattern, buffer);
 28.1987 +            positiveSuffixFieldPositions = null;
 28.1988 +        }
 28.1989 +        if (negPrefixPattern != null) {
 28.1990 +            negativePrefix = expandAffix(negPrefixPattern, buffer);
 28.1991 +            negativePrefixFieldPositions = null;
 28.1992 +        }
 28.1993 +        if (negSuffixPattern != null) {
 28.1994 +            negativeSuffix = expandAffix(negSuffixPattern, buffer);
 28.1995 +            negativeSuffixFieldPositions = null;
 28.1996 +        }
 28.1997 +    }
 28.1998 +
 28.1999 +    /**
 28.2000 +     * Expand an affix pattern into an affix string.  All characters in the
 28.2001 +     * pattern are literal unless prefixed by QUOTE.  The following characters
 28.2002 +     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
 28.2003 +     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
 28.2004 +     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
 28.2005 +     * currency code.  Any other character after a QUOTE represents itself.
 28.2006 +     * QUOTE must be followed by another character; QUOTE may not occur by
 28.2007 +     * itself at the end of the pattern.
 28.2008 +     *
 28.2009 +     * @param pattern the non-null, possibly empty pattern
 28.2010 +     * @param buffer a scratch StringBuffer; its contents will be lost
 28.2011 +     * @return the expanded equivalent of pattern
 28.2012 +     */
 28.2013 +    private String expandAffix(String pattern, StringBuffer buffer) {
 28.2014 +        buffer.setLength(0);
 28.2015 +        for (int i=0; i<pattern.length(); ) {
 28.2016 +            char c = pattern.charAt(i++);
 28.2017 +            if (c == QUOTE) {
 28.2018 +                c = pattern.charAt(i++);
 28.2019 +                switch (c) {
 28.2020 +                case CURRENCY_SIGN:
 28.2021 +                    if (i<pattern.length() &&
 28.2022 +                        pattern.charAt(i) == CURRENCY_SIGN) {
 28.2023 +                        ++i;
 28.2024 +                        buffer.append(symbols.getInternationalCurrencySymbol());
 28.2025 +                    } else {
 28.2026 +                        buffer.append(symbols.getCurrencySymbol());
 28.2027 +                    }
 28.2028 +                    continue;
 28.2029 +                case PATTERN_PERCENT:
 28.2030 +                    c = symbols.getPercent();
 28.2031 +                    break;
 28.2032 +                case PATTERN_PER_MILLE:
 28.2033 +                    c = symbols.getPerMill();
 28.2034 +                    break;
 28.2035 +                case PATTERN_MINUS:
 28.2036 +                    c = symbols.getMinusSign();
 28.2037 +                    break;
 28.2038 +                }
 28.2039 +            }
 28.2040 +            buffer.append(c);
 28.2041 +        }
 28.2042 +        return buffer.toString();
 28.2043 +    }
 28.2044 +
 28.2045 +    /**
 28.2046 +     * Expand an affix pattern into an array of FieldPositions describing
 28.2047 +     * how the pattern would be expanded.
 28.2048 +     * All characters in the
 28.2049 +     * pattern are literal unless prefixed by QUOTE.  The following characters
 28.2050 +     * after QUOTE are recognized: PATTERN_PERCENT, PATTERN_PER_MILLE,
 28.2051 +     * PATTERN_MINUS, and CURRENCY_SIGN.  If CURRENCY_SIGN is doubled (QUOTE +
 28.2052 +     * CURRENCY_SIGN + CURRENCY_SIGN), it is interpreted as an ISO 4217
 28.2053 +     * currency code.  Any other character after a QUOTE represents itself.
 28.2054 +     * QUOTE must be followed by another character; QUOTE may not occur by
 28.2055 +     * itself at the end of the pattern.
 28.2056 +     *
 28.2057 +     * @param pattern the non-null, possibly empty pattern
 28.2058 +     * @return FieldPosition array of the resulting fields.
 28.2059 +     */
 28.2060 +    private FieldPosition[] expandAffix(String pattern) {
 28.2061 +        ArrayList positions = null;
 28.2062 +        int stringIndex = 0;
 28.2063 +        for (int i=0; i<pattern.length(); ) {
 28.2064 +            char c = pattern.charAt(i++);
 28.2065 +            if (c == QUOTE) {
 28.2066 +                int field = -1;
 28.2067 +                Format.Field fieldID = null;
 28.2068 +                c = pattern.charAt(i++);
 28.2069 +                switch (c) {
 28.2070 +                case CURRENCY_SIGN:
 28.2071 +                    String string;
 28.2072 +                    if (i<pattern.length() &&
 28.2073 +                        pattern.charAt(i) == CURRENCY_SIGN) {
 28.2074 +                        ++i;
 28.2075 +                        string = symbols.getInternationalCurrencySymbol();
 28.2076 +                    } else {
 28.2077 +                        string = symbols.getCurrencySymbol();
 28.2078 +                    }
 28.2079 +                    if (string.length() > 0) {
 28.2080 +                        if (positions == null) {
 28.2081 +                            positions = new ArrayList(2);
 28.2082 +                        }
 28.2083 +                        FieldPosition fp = new FieldPosition(Field.CURRENCY);
 28.2084 +                        fp.setBeginIndex(stringIndex);
 28.2085 +                        fp.setEndIndex(stringIndex + string.length());
 28.2086 +                        positions.add(fp);
 28.2087 +                        stringIndex += string.length();
 28.2088 +                    }
 28.2089 +                    continue;
 28.2090 +                case PATTERN_PERCENT:
 28.2091 +                    c = symbols.getPercent();
 28.2092 +                    field = -1;
 28.2093 +                    fieldID = Field.PERCENT;
 28.2094 +                    break;
 28.2095 +                case PATTERN_PER_MILLE:
 28.2096 +                    c = symbols.getPerMill();
 28.2097 +                    field = -1;
 28.2098 +                    fieldID = Field.PERMILLE;
 28.2099 +                    break;
 28.2100 +                case PATTERN_MINUS:
 28.2101 +                    c = symbols.getMinusSign();
 28.2102 +                    field = -1;
 28.2103 +                    fieldID = Field.SIGN;
 28.2104 +                    break;
 28.2105 +                }
 28.2106 +                if (fieldID != null) {
 28.2107 +                    if (positions == null) {
 28.2108 +                        positions = new ArrayList(2);
 28.2109 +                    }
 28.2110 +                    FieldPosition fp = new FieldPosition(fieldID, field);
 28.2111 +                    fp.setBeginIndex(stringIndex);
 28.2112 +                    fp.setEndIndex(stringIndex + 1);
 28.2113 +                    positions.add(fp);
 28.2114 +                }
 28.2115 +            }
 28.2116 +            stringIndex++;
 28.2117 +        }
 28.2118 +        if (positions != null) {
 28.2119 +            return (FieldPosition[])positions.toArray(EmptyFieldPositionArray);
 28.2120 +        }
 28.2121 +        return EmptyFieldPositionArray;
 28.2122 +    }
 28.2123 +
 28.2124 +    /**
 28.2125 +     * Appends an affix pattern to the given StringBuffer, quoting special
 28.2126 +     * characters as needed.  Uses the internal affix pattern, if that exists,
 28.2127 +     * or the literal affix, if the internal affix pattern is null.  The
 28.2128 +     * appended string will generate the same affix pattern (or literal affix)
 28.2129 +     * when passed to toPattern().
 28.2130 +     *
 28.2131 +     * @param buffer the affix string is appended to this
 28.2132 +     * @param affixPattern a pattern such as posPrefixPattern; may be null
 28.2133 +     * @param expAffix a corresponding expanded affix, such as positivePrefix.
 28.2134 +     * Ignored unless affixPattern is null.  If affixPattern is null, then
 28.2135 +     * expAffix is appended as a literal affix.
 28.2136 +     * @param localized true if the appended pattern should contain localized
 28.2137 +     * pattern characters; otherwise, non-localized pattern chars are appended
 28.2138 +     */
 28.2139 +    private void appendAffix(StringBuffer buffer, String affixPattern,
 28.2140 +                             String expAffix, boolean localized) {
 28.2141 +        if (affixPattern == null) {
 28.2142 +            appendAffix(buffer, expAffix, localized);
 28.2143 +        } else {
 28.2144 +            int i;
 28.2145 +            for (int pos=0; pos<affixPattern.length(); pos=i) {
 28.2146 +                i = affixPattern.indexOf(QUOTE, pos);
 28.2147 +                if (i < 0) {
 28.2148 +                    appendAffix(buffer, affixPattern.substring(pos), localized);
 28.2149 +                    break;
 28.2150 +                }
 28.2151 +                if (i > pos) {
 28.2152 +                    appendAffix(buffer, affixPattern.substring(pos, i), localized);
 28.2153 +                }
 28.2154 +                char c = affixPattern.charAt(++i);
 28.2155 +                ++i;
 28.2156 +                if (c == QUOTE) {
 28.2157 +                    buffer.append(c);
 28.2158 +                    // Fall through and append another QUOTE below
 28.2159 +                } else if (c == CURRENCY_SIGN &&
 28.2160 +                           i<affixPattern.length() &&
 28.2161 +                           affixPattern.charAt(i) == CURRENCY_SIGN) {
 28.2162 +                    ++i;
 28.2163 +                    buffer.append(c);
 28.2164 +                    // Fall through and append another CURRENCY_SIGN below
 28.2165 +                } else if (localized) {
 28.2166 +                    switch (c) {
 28.2167 +                    case PATTERN_PERCENT:
 28.2168 +                        c = symbols.getPercent();
 28.2169 +                        break;
 28.2170 +                    case PATTERN_PER_MILLE:
 28.2171 +                        c = symbols.getPerMill();
 28.2172 +                        break;
 28.2173 +                    case PATTERN_MINUS:
 28.2174 +                        c = symbols.getMinusSign();
 28.2175 +                        break;
 28.2176 +                    }
 28.2177 +                }
 28.2178 +                buffer.append(c);
 28.2179 +            }
 28.2180 +        }
 28.2181 +    }
 28.2182 +
 28.2183 +    /**
 28.2184 +     * Append an affix to the given StringBuffer, using quotes if
 28.2185 +     * there are special characters.  Single quotes themselves must be
 28.2186 +     * escaped in either case.
 28.2187 +     */
 28.2188 +    private void appendAffix(StringBuffer buffer, String affix, boolean localized) {
 28.2189 +        boolean needQuote;
 28.2190 +        if (localized) {
 28.2191 +            needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
 28.2192 +                || affix.indexOf(symbols.getGroupingSeparator()) >= 0
 28.2193 +                || affix.indexOf(symbols.getDecimalSeparator()) >= 0
 28.2194 +                || affix.indexOf(symbols.getPercent()) >= 0
 28.2195 +                || affix.indexOf(symbols.getPerMill()) >= 0
 28.2196 +                || affix.indexOf(symbols.getDigit()) >= 0
 28.2197 +                || affix.indexOf(symbols.getPatternSeparator()) >= 0
 28.2198 +                || affix.indexOf(symbols.getMinusSign()) >= 0
 28.2199 +                || affix.indexOf(CURRENCY_SIGN) >= 0;
 28.2200 +        }
 28.2201 +        else {
 28.2202 +            needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
 28.2203 +                || affix.indexOf(PATTERN_GROUPING_SEPARATOR) >= 0
 28.2204 +                || affix.indexOf(PATTERN_DECIMAL_SEPARATOR) >= 0
 28.2205 +                || affix.indexOf(PATTERN_PERCENT) >= 0
 28.2206 +                || affix.indexOf(PATTERN_PER_MILLE) >= 0
 28.2207 +                || affix.indexOf(PATTERN_DIGIT) >= 0
 28.2208 +                || affix.indexOf(PATTERN_SEPARATOR) >= 0
 28.2209 +                || affix.indexOf(PATTERN_MINUS) >= 0
 28.2210 +                || affix.indexOf(CURRENCY_SIGN) >= 0;
 28.2211 +        }
 28.2212 +        if (needQuote) buffer.append('\'');
 28.2213 +        if (affix.indexOf('\'') < 0) buffer.append(affix);
 28.2214 +        else {
 28.2215 +            for (int j=0; j<affix.length(); ++j) {
 28.2216 +                char c = affix.charAt(j);
 28.2217 +                buffer.append(c);
 28.2218 +                if (c == '\'') buffer.append(c);
 28.2219 +            }
 28.2220 +        }
 28.2221 +        if (needQuote) buffer.append('\'');
 28.2222 +    }
 28.2223 +
 28.2224 +    /**
 28.2225 +     * Does the real work of generating a pattern.  */
 28.2226 +    private String toPattern(boolean localized) {
 28.2227 +        StringBuffer result = new StringBuffer();
 28.2228 +        for (int j = 1; j >= 0; --j) {
 28.2229 +            if (j == 1)
 28.2230 +                appendAffix(result, posPrefixPattern, positivePrefix, localized);
 28.2231 +            else appendAffix(result, negPrefixPattern, negativePrefix, localized);
 28.2232 +            int i;
 28.2233 +            int digitCount = useExponentialNotation
 28.2234 +                        ? getMaximumIntegerDigits()
 28.2235 +                        : Math.max(groupingSize, getMinimumIntegerDigits())+1;
 28.2236 +            for (i = digitCount; i > 0; --i) {
 28.2237 +                if (i != digitCount && isGroupingUsed() && groupingSize != 0 &&
 28.2238 +                    i % groupingSize == 0) {
 28.2239 +                    result.append(localized ? symbols.getGroupingSeparator() :
 28.2240 +                                  PATTERN_GROUPING_SEPARATOR);
 28.2241 +                }
 28.2242 +                result.append(i <= getMinimumIntegerDigits()
 28.2243 +                    ? (localized ? symbols.getZeroDigit() : PATTERN_ZERO_DIGIT)
 28.2244 +                    : (localized ? symbols.getDigit() : PATTERN_DIGIT));
 28.2245 +            }
 28.2246 +            if (getMaximumFractionDigits() > 0 || decimalSeparatorAlwaysShown)
 28.2247 +                result.append(localized ? symbols.getDecimalSeparator() :
 28.2248 +                              PATTERN_DECIMAL_SEPARATOR);
 28.2249 +            for (i = 0; i < getMaximumFractionDigits(); ++i) {
 28.2250 +                if (i < getMinimumFractionDigits()) {
 28.2251 +                    result.append(localized ? symbols.getZeroDigit() :
 28.2252 +                                  PATTERN_ZERO_DIGIT);
 28.2253 +                } else {
 28.2254 +                    result.append(localized ? symbols.getDigit() :
 28.2255 +                                  PATTERN_DIGIT);
 28.2256 +                }
 28.2257 +            }
 28.2258 +        if (useExponentialNotation)
 28.2259 +        {
 28.2260 +            result.append(localized ? symbols.getExponentSeparator() :
 28.2261 +                  PATTERN_EXPONENT);
 28.2262 +        for (i=0; i<minExponentDigits; ++i)
 28.2263 +                    result.append(localized ? symbols.getZeroDigit() :
 28.2264 +                                  PATTERN_ZERO_DIGIT);
 28.2265 +        }
 28.2266 +            if (j == 1) {
 28.2267 +                appendAffix(result, posSuffixPattern, positiveSuffix, localized);
 28.2268 +                if ((negSuffixPattern == posSuffixPattern && // n == p == null
 28.2269 +                     negativeSuffix.equals(positiveSuffix))
 28.2270 +                    || (negSuffixPattern != null &&
 28.2271 +                        negSuffixPattern.equals(posSuffixPattern))) {
 28.2272 +                    if ((negPrefixPattern != null && posPrefixPattern != null &&
 28.2273 +                         negPrefixPattern.equals("'-" + posPrefixPattern)) ||
 28.2274 +                        (negPrefixPattern == posPrefixPattern && // n == p == null
 28.2275 +                         negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
 28.2276 +                        break;
 28.2277 +                }
 28.2278 +                result.append(localized ? symbols.getPatternSeparator() :
 28.2279 +                              PATTERN_SEPARATOR);
 28.2280 +            } else appendAffix(result, negSuffixPattern, negativeSuffix, localized);
 28.2281 +        }
 28.2282 +        return result.toString();
 28.2283 +    }
 28.2284 +
 28.2285 +    /**
 28.2286 +     * Apply the given pattern to this Format object.  A pattern is a
 28.2287 +     * short-hand specification for the various formatting properties.
 28.2288 +     * These properties can also be changed individually through the
 28.2289 +     * various setter methods.
 28.2290 +     * <p>
 28.2291 +     * There is no limit to integer digits set
 28.2292 +     * by this routine, since that is the typical end-user desire;
 28.2293 +     * use setMaximumInteger if you want to set a real value.
 28.2294 +     * For negative numbers, use a second pattern, separated by a semicolon
 28.2295 +     * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
 28.2296 +     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
 28.2297 +     * a maximum of 2 fraction digits.
 28.2298 +     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
 28.2299 +     * parentheses.
 28.2300 +     * <p>In negative patterns, the minimum and maximum counts are ignored;
 28.2301 +     * these are presumed to be set in the positive pattern.
 28.2302 +     *
 28.2303 +     * @exception NullPointerException if <code>pattern</code> is null
 28.2304 +     * @exception IllegalArgumentException if the given pattern is invalid.
 28.2305 +     */
 28.2306 +    public void applyPattern(String pattern) {
 28.2307 +        applyPattern(pattern, false);
 28.2308 +    }
 28.2309 +
 28.2310 +    /**
 28.2311 +     * Apply the given pattern to this Format object.  The pattern
 28.2312 +     * is assumed to be in a localized notation. A pattern is a
 28.2313 +     * short-hand specification for the various formatting properties.
 28.2314 +     * These properties can also be changed individually through the
 28.2315 +     * various setter methods.
 28.2316 +     * <p>
 28.2317 +     * There is no limit to integer digits set
 28.2318 +     * by this routine, since that is the typical end-user desire;
 28.2319 +     * use setMaximumInteger if you want to set a real value.
 28.2320 +     * For negative numbers, use a second pattern, separated by a semicolon
 28.2321 +     * <P>Example <code>"#,#00.0#"</code> -> 1,234.56
 28.2322 +     * <P>This means a minimum of 2 integer digits, 1 fraction digit, and
 28.2323 +     * a maximum of 2 fraction digits.
 28.2324 +     * <p>Example: <code>"#,#00.0#;(#,#00.0#)"</code> for negatives in
 28.2325 +     * parentheses.
 28.2326 +     * <p>In negative patterns, the minimum and maximum counts are ignored;
 28.2327 +     * these are presumed to be set in the positive pattern.
 28.2328 +     *
 28.2329 +     * @exception NullPointerException if <code>pattern</code> is null
 28.2330 +     * @exception IllegalArgumentException if the given pattern is invalid.
 28.2331 +     */
 28.2332 +    public void applyLocalizedPattern(String pattern) {
 28.2333 +        applyPattern(pattern, true);
 28.2334 +    }
 28.2335 +
 28.2336 +    /**
 28.2337 +     * Does the real work of applying a pattern.
 28.2338 +     */
 28.2339 +    private void applyPattern(String pattern, boolean localized) {
 28.2340 +        char zeroDigit         = PATTERN_ZERO_DIGIT;
 28.2341 +        char groupingSeparator = PATTERN_GROUPING_SEPARATOR;
 28.2342 +        char decimalSeparator  = PATTERN_DECIMAL_SEPARATOR;
 28.2343 +        char percent           = PATTERN_PERCENT;
 28.2344 +        char perMill           = PATTERN_PER_MILLE;
 28.2345 +        char digit             = PATTERN_DIGIT;
 28.2346 +        char separator         = PATTERN_SEPARATOR;
 28.2347 +        String exponent          = PATTERN_EXPONENT;
 28.2348 +        char minus             = PATTERN_MINUS;
 28.2349 +        if (localized) {
 28.2350 +            zeroDigit         = symbols.getZeroDigit();
 28.2351 +            groupingSeparator = symbols.getGroupingSeparator();
 28.2352 +            decimalSeparator  = symbols.getDecimalSeparator();
 28.2353 +            percent           = symbols.getPercent();
 28.2354 +            perMill           = symbols.getPerMill();
 28.2355 +            digit             = symbols.getDigit();
 28.2356 +            separator         = symbols.getPatternSeparator();
 28.2357 +            exponent          = symbols.getExponentSeparator();
 28.2358 +            minus             = symbols.getMinusSign();
 28.2359 +        }
 28.2360 +        boolean gotNegative = false;
 28.2361 +        decimalSeparatorAlwaysShown = false;
 28.2362 +        isCurrencyFormat = false;
 28.2363 +        useExponentialNotation = false;
 28.2364 +
 28.2365 +        // Two variables are used to record the subrange of the pattern
 28.2366 +        // occupied by phase 1.  This is used during the processing of the
 28.2367 +        // second pattern (the one representing negative numbers) to ensure
 28.2368 +        // that no deviation exists in phase 1 between the two patterns.
 28.2369 +        int phaseOneStart = 0;
 28.2370 +        int phaseOneLength = 0;
 28.2371 +
 28.2372 +        int start = 0;
 28.2373 +        for (int j = 1; j >= 0 && start < pattern.length(); --j) {
 28.2374 +            boolean inQuote = false;
 28.2375 +            StringBuffer prefix = new StringBuffer();
 28.2376 +            StringBuffer suffix = new StringBuffer();
 28.2377 +            int decimalPos = -1;
 28.2378 +            int multiplier = 1;
 28.2379 +            int digitLeftCount = 0, zeroDigitCount = 0, digitRightCount = 0;
 28.2380 +            byte groupingCount = -1;
 28.2381 +
 28.2382 +            // The phase ranges from 0 to 2.  Phase 0 is the prefix.  Phase 1 is
 28.2383 +            // the section of the pattern with digits, decimal separator,
 28.2384 +            // grouping characters.  Phase 2 is the suffix.  In phases 0 and 2,
 28.2385 +            // percent, per mille, and currency symbols are recognized and
 28.2386 +            // translated.  The separation of the characters into phases is
 28.2387 +            // strictly enforced; if phase 1 characters are to appear in the
 28.2388 +            // suffix, for example, they must be quoted.
 28.2389 +            int phase = 0;
 28.2390 +
 28.2391 +            // The affix is either the prefix or the suffix.
 28.2392 +            StringBuffer affix = prefix;
 28.2393 +
 28.2394 +            for (int pos = start; pos < pattern.length(); ++pos) {
 28.2395 +                char ch = pattern.charAt(pos);
 28.2396 +                switch (phase) {
 28.2397 +                case 0:
 28.2398 +                case 2:
 28.2399 +                    // Process the prefix / suffix characters
 28.2400 +                    if (inQuote) {
 28.2401 +                        // A quote within quotes indicates either the closing
 28.2402 +                        // quote or two quotes, which is a quote literal. That
 28.2403 +                        // is, we have the second quote in 'do' or 'don''t'.
 28.2404 +                        if (ch == QUOTE) {
 28.2405 +                            if ((pos+1) < pattern.length() &&
 28.2406 +                                pattern.charAt(pos+1) == QUOTE) {
 28.2407 +                                ++pos;
 28.2408 +                                affix.append("''"); // 'don''t'
 28.2409 +                            } else {
 28.2410 +                                inQuote = false; // 'do'
 28.2411 +                            }
 28.2412 +                            continue;
 28.2413 +                        }
 28.2414 +                    } else {
 28.2415 +                        // Process unquoted characters seen in prefix or suffix
 28.2416 +                        // phase.
 28.2417 +                        if (ch == digit ||
 28.2418 +                            ch == zeroDigit ||
 28.2419 +                            ch == groupingSeparator ||
 28.2420 +                            ch == decimalSeparator) {
 28.2421 +                            phase = 1;
 28.2422 +                            if (j == 1) {
 28.2423 +                                phaseOneStart = pos;
 28.2424 +                            }
 28.2425 +                            --pos; // Reprocess this character
 28.2426 +                            continue;
 28.2427 +                        } else if (ch == CURRENCY_SIGN) {
 28.2428 +                            // Use lookahead to determine if the currency sign
 28.2429 +                            // is doubled or not.
 28.2430 +                            boolean doubled = (pos + 1) < pattern.length() &&
 28.2431 +                                pattern.charAt(pos + 1) == CURRENCY_SIGN;
 28.2432 +                            if (doubled) { // Skip over the doubled character
 28.2433 +                             ++pos;
 28.2434 +                            }
 28.2435 +                            isCurrencyFormat = true;
 28.2436 +                            affix.append(doubled ? "'\u00A4\u00A4" : "'\u00A4");
 28.2437 +                            continue;
 28.2438 +                        } else if (ch == QUOTE) {
 28.2439 +                            // A quote outside quotes indicates either the
 28.2440 +                            // opening quote or two quotes, which is a quote
 28.2441 +                            // literal. That is, we have the first quote in 'do'
 28.2442 +                            // or o''clock.
 28.2443 +                            if (ch == QUOTE) {
 28.2444 +                                if ((pos+1) < pattern.length() &&
 28.2445 +                                    pattern.charAt(pos+1) == QUOTE) {
 28.2446 +                                    ++pos;
 28.2447 +                                    affix.append("''"); // o''clock
 28.2448 +                                } else {
 28.2449 +                                    inQuote = true; // 'do'
 28.2450 +                                }
 28.2451 +                                continue;
 28.2452 +                            }
 28.2453 +                        } else if (ch == separator) {
 28.2454 +                            // Don't allow separators before we see digit
 28.2455 +                            // characters of phase 1, and don't allow separators
 28.2456 +                            // in the second pattern (j == 0).
 28.2457 +                            if (phase == 0 || j == 0) {
 28.2458 +                                throw new IllegalArgumentException("Unquoted special character '" +
 28.2459 +                                    ch + "' in pattern \"" + pattern + '"');
 28.2460 +                            }
 28.2461 +                            start = pos + 1;
 28.2462 +                            pos = pattern.length();
 28.2463 +                            continue;
 28.2464 +                        }
 28.2465 +
 28.2466 +                        // Next handle characters which are appended directly.
 28.2467 +                        else if (ch == percent) {
 28.2468 +                            if (multiplier != 1) {
 28.2469 +                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
 28.2470 +                                    pattern + '"');
 28.2471 +                            }
 28.2472 +                            multiplier = 100;
 28.2473 +                            affix.append("'%");
 28.2474 +                            continue;
 28.2475 +                        } else if (ch == perMill) {
 28.2476 +                            if (multiplier != 1) {
 28.2477 +                                throw new IllegalArgumentException("Too many percent/per mille characters in pattern \"" +
 28.2478 +                                    pattern + '"');
 28.2479 +                            }
 28.2480 +                            multiplier = 1000;
 28.2481 +                            affix.append("'\u2030");
 28.2482 +                            continue;
 28.2483 +                        } else if (ch == minus) {
 28.2484 +                            affix.append("'-");
 28.2485 +                            continue;
 28.2486 +                        }
 28.2487 +                    }
 28.2488 +                    // Note that if we are within quotes, or if this is an
 28.2489 +                    // unquoted, non-special character, then we usually fall
 28.2490 +                    // through to here.
 28.2491 +                    affix.append(ch);
 28.2492 +                    break;
 28.2493 +
 28.2494 +                case 1:
 28.2495 +                    // Phase one must be identical in the two sub-patterns. We
 28.2496 +                    // enforce this by doing a direct comparison. While
 28.2497 +                    // processing the first sub-pattern, we just record its
 28.2498 +                    // length. While processing the second, we compare
 28.2499 +                    // characters.
 28.2500 +                    if (j == 1) {
 28.2501 +                        ++phaseOneLength;
 28.2502 +                    } else {
 28.2503 +                        if (--phaseOneLength == 0) {
 28.2504 +                            phase = 2;
 28.2505 +                            affix = suffix;
 28.2506 +                        }
 28.2507 +                        continue;
 28.2508 +                    }
 28.2509 +
 28.2510 +                    // Process the digits, decimal, and grouping characters. We
 28.2511 +                    // record five pieces of information. We expect the digits
 28.2512 +                    // to occur in the pattern ####0000.####, and we record the
 28.2513 +                    // number of left digits, zero (central) digits, and right
 28.2514 +                    // digits. The position of the last grouping character is
 28.2515 +                    // recorded (should be somewhere within the first two blocks
 28.2516 +                    // of characters), as is the position of the decimal point,
 28.2517 +                    // if any (should be in the zero digits). If there is no
 28.2518 +                    // decimal point, then there should be no right digits.
 28.2519 +                    if (ch == digit) {
 28.2520 +                        if (zeroDigitCount > 0) {
 28.2521 +                            ++digitRightCount;
 28.2522 +                        } else {
 28.2523 +                            ++digitLeftCount;
 28.2524 +                        }
 28.2525 +                        if (groupingCount >= 0 && decimalPos < 0) {
 28.2526 +                            ++groupingCount;
 28.2527 +                        }
 28.2528 +                    } else if (ch == zeroDigit) {
 28.2529 +                        if (digitRightCount > 0) {
 28.2530 +                            throw new IllegalArgumentException("Unexpected '0' in pattern \"" +
 28.2531 +                                pattern + '"');
 28.2532 +                        }
 28.2533 +                        ++zeroDigitCount;
 28.2534 +                        if (groupingCount >= 0 && decimalPos < 0) {
 28.2535 +                            ++groupingCount;
 28.2536 +                        }
 28.2537 +                    } else if (ch == groupingSeparator) {
 28.2538 +                        groupingCount = 0;
 28.2539 +                    } else if (ch == decimalSeparator) {
 28.2540 +                        if (decimalPos >= 0) {
 28.2541 +                            throw new IllegalArgumentException("Multiple decimal separators in pattern \"" +
 28.2542 +                                pattern + '"');
 28.2543 +                        }
 28.2544 +                        decimalPos = digitLeftCount + zeroDigitCount + digitRightCount;
 28.2545 +                    } else if (pattern.regionMatches(pos, exponent, 0, exponent.length())){
 28.2546 +                        if (useExponentialNotation) {
 28.2547 +                            throw new IllegalArgumentException("Multiple exponential " +
 28.2548 +                                "symbols in pattern \"" + pattern + '"');
 28.2549 +                        }
 28.2550 +                        useExponentialNotation = true;
 28.2551 +                        minExponentDigits = 0;
 28.2552 +
 28.2553 +                        // Use lookahead to parse out the exponential part
 28.2554 +                        // of the pattern, then jump into phase 2.
 28.2555 +                        pos = pos+exponent.length();
 28.2556 +                         while (pos < pattern.length() &&
 28.2557 +                               pattern.charAt(pos) == zeroDigit) {
 28.2558 +                            ++minExponentDigits;
 28.2559 +                            ++phaseOneLength;
 28.2560 +                            ++pos;
 28.2561 +                        }
 28.2562 +
 28.2563 +                        if ((digitLeftCount + zeroDigitCount) < 1 ||
 28.2564 +                            minExponentDigits < 1) {
 28.2565 +                            throw new IllegalArgumentException("Malformed exponential " +
 28.2566 +                                "pattern \"" + pattern + '"');
 28.2567 +                        }
 28.2568 +
 28.2569 +                        // Transition to phase 2
 28.2570 +                        phase = 2;
 28.2571 +                        affix = suffix;
 28.2572 +                        --pos;
 28.2573 +                        continue;
 28.2574 +                    } else {
 28.2575 +                        phase = 2;
 28.2576 +                        affix = suffix;
 28.2577 +                        --pos;
 28.2578 +                        --phaseOneLength;
 28.2579 +                        continue;
 28.2580 +                    }
 28.2581 +                    break;
 28.2582 +                }
 28.2583 +            }
 28.2584 +
 28.2585 +            // Handle patterns with no '0' pattern character. These patterns
 28.2586 +            // are legal, but must be interpreted.  "##.###" -> "#0.###".
 28.2587 +            // ".###" -> ".0##".
 28.2588 +            /* We allow patterns of the form "####" to produce a zeroDigitCount
 28.2589 +             * of zero (got that?); although this seems like it might make it
 28.2590 +             * possible for format() to produce empty strings, format() checks
 28.2591 +             * for this condition and outputs a zero digit in this situation.
 28.2592 +             * Having a zeroDigitCount of zero yields a minimum integer digits
 28.2593 +             * of zero, which allows proper round-trip patterns.  That is, we
 28.2594 +             * don't want "#" to become "#0" when toPattern() is called (even
 28.2595 +             * though that's what it really is, semantically).
 28.2596 +             */
 28.2597 +            if (zeroDigitCount == 0 && digitLeftCount > 0 && decimalPos >= 0) {
 28.2598 +                // Handle "###.###" and "###." and ".###"
 28.2599 +                int n = decimalPos;
 28.2600 +                if (n == 0) { // Handle ".###"
 28.2601 +                    ++n;
 28.2602 +                }
 28.2603 +                digitRightCount = digitLeftCount - n;
 28.2604 +                digitLeftCount = n - 1;
 28.2605 +                zeroDigitCount = 1;
 28.2606 +            }
 28.2607 +
 28.2608 +            // Do syntax checking on the digits.
 28.2609 +            if ((decimalPos < 0 && digitRightCount > 0) ||
 28.2610 +                (decimalPos >= 0 && (decimalPos < digitLeftCount ||
 28.2611 +                 decimalPos > (digitLeftCount + zeroDigitCount))) ||
 28.2612 +                 groupingCount == 0 || inQuote) {
 28.2613 +                throw new IllegalArgumentException("Malformed pattern \"" +
 28.2614 +                    pattern + '"');
 28.2615 +            }
 28.2616 +
 28.2617 +            if (j == 1) {
 28.2618 +                posPrefixPattern = prefix.toString();
 28.2619 +                posSuffixPattern = suffix.toString();
 28.2620 +                negPrefixPattern = posPrefixPattern;   // assume these for now
 28.2621 +                negSuffixPattern = posSuffixPattern;
 28.2622 +                int digitTotalCount = digitLeftCount + zeroDigitCount + digitRightCount;
 28.2623 +                /* The effectiveDecimalPos is the position the decimal is at or
 28.2624 +                 * would be at if there is no decimal. Note that if decimalPos<0,
 28.2625 +                 * then digitTotalCount == digitLeftCount + zeroDigitCount.
 28.2626 +                 */
 28.2627 +                int effectiveDecimalPos = decimalPos >= 0 ?
 28.2628 +                    decimalPos : digitTotalCount;
 28.2629 +                setMinimumIntegerDigits(effectiveDecimalPos - digitLeftCount);
 28.2630 +                setMaximumIntegerDigits(useExponentialNotation ?
 28.2631 +                    digitLeftCount + getMinimumIntegerDigits() :
 28.2632 +                    MAXIMUM_INTEGER_DIGITS);
 28.2633 +                setMaximumFractionDigits(decimalPos >= 0 ?
 28.2634 +                    (digitTotalCount - decimalPos) : 0);
 28.2635 +                setMinimumFractionDigits(decimalPos >= 0 ?
 28.2636 +                    (digitLeftCount + zeroDigitCount - decimalPos) : 0);
 28.2637 +                setGroupingUsed(groupingCount > 0);
 28.2638 +                this.groupingSize = (groupingCount > 0) ? groupingCount : 0;
 28.2639 +                this.multiplier = multiplier;
 28.2640 +                setDecimalSeparatorAlwaysShown(decimalPos == 0 ||
 28.2641 +                    decimalPos == digitTotalCount);
 28.2642 +            } else {
 28.2643 +                negPrefixPattern = prefix.toString();
 28.2644 +                negSuffixPattern = suffix.toString();
 28.2645 +                gotNegative = true;
 28.2646 +            }
 28.2647 +        }
 28.2648 +
 28.2649 +        if (pattern.length() == 0) {
 28.2650 +            posPrefixPattern = posSuffixPattern = "";
 28.2651 +            setMinimumIntegerDigits(0);
 28.2652 +            setMaximumIntegerDigits(MAXIMUM_INTEGER_DIGITS);
 28.2653 +            setMinimumFractionDigits(0);
 28.2654 +            setMaximumFractionDigits(MAXIMUM_FRACTION_DIGITS);
 28.2655 +        }
 28.2656 +
 28.2657 +        // If there was no negative pattern, or if the negative pattern is
 28.2658 +        // identical to the positive pattern, then prepend the minus sign to
 28.2659 +        // the positive pattern to form the negative pattern.
 28.2660 +        if (!gotNegative ||
 28.2661 +            (negPrefixPattern.equals(posPrefixPattern)
 28.2662 +             && negSuffixPattern.equals(posSuffixPattern))) {
 28.2663 +            negSuffixPattern = posSuffixPattern;
 28.2664 +            negPrefixPattern = "'-" + posPrefixPattern;
 28.2665 +        }
 28.2666 +
 28.2667 +        expandAffixes();
 28.2668 +    }
 28.2669 +
 28.2670 +    /**
 28.2671 +     * Sets the maximum number of digits allowed in the integer portion of a
 28.2672 +     * number.
 28.2673 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2674 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
 28.2675 +     * 309 is used. Negative input values are replaced with 0.
 28.2676 +     * @see NumberFormat#setMaximumIntegerDigits
 28.2677 +     */
 28.2678 +    public void setMaximumIntegerDigits(int newValue) {
 28.2679 +        maximumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
 28.2680 +        super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
 28.2681 +            DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
 28.2682 +        if (minimumIntegerDigits > maximumIntegerDigits) {
 28.2683 +            minimumIntegerDigits = maximumIntegerDigits;
 28.2684 +            super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
 28.2685 +                DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
 28.2686 +        }
 28.2687 +    }
 28.2688 +
 28.2689 +    /**
 28.2690 +     * Sets the minimum number of digits allowed in the integer portion of a
 28.2691 +     * number.
 28.2692 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2693 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
 28.2694 +     * 309 is used. Negative input values are replaced with 0.
 28.2695 +     * @see NumberFormat#setMinimumIntegerDigits
 28.2696 +     */
 28.2697 +    public void setMinimumIntegerDigits(int newValue) {
 28.2698 +        minimumIntegerDigits = Math.min(Math.max(0, newValue), MAXIMUM_INTEGER_DIGITS);
 28.2699 +        super.setMinimumIntegerDigits((minimumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
 28.2700 +            DOUBLE_INTEGER_DIGITS : minimumIntegerDigits);
 28.2701 +        if (minimumIntegerDigits > maximumIntegerDigits) {
 28.2702 +            maximumIntegerDigits = minimumIntegerDigits;
 28.2703 +            super.setMaximumIntegerDigits((maximumIntegerDigits > DOUBLE_INTEGER_DIGITS) ?
 28.2704 +                DOUBLE_INTEGER_DIGITS : maximumIntegerDigits);
 28.2705 +        }
 28.2706 +    }
 28.2707 +
 28.2708 +    /**
 28.2709 +     * Sets the maximum number of digits allowed in the fraction portion of a
 28.2710 +     * number.
 28.2711 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2712 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
 28.2713 +     * 340 is used. Negative input values are replaced with 0.
 28.2714 +     * @see NumberFormat#setMaximumFractionDigits
 28.2715 +     */
 28.2716 +    public void setMaximumFractionDigits(int newValue) {
 28.2717 +        maximumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
 28.2718 +        super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
 28.2719 +            DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
 28.2720 +        if (minimumFractionDigits > maximumFractionDigits) {
 28.2721 +            minimumFractionDigits = maximumFractionDigits;
 28.2722 +            super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
 28.2723 +                DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
 28.2724 +        }
 28.2725 +    }
 28.2726 +
 28.2727 +    /**
 28.2728 +     * Sets the minimum number of digits allowed in the fraction portion of a
 28.2729 +     * number.
 28.2730 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2731 +     * <code>BigDecimal</code> objects, the lower of <code>newValue</code> and
 28.2732 +     * 340 is used. Negative input values are replaced with 0.
 28.2733 +     * @see NumberFormat#setMinimumFractionDigits
 28.2734 +     */
 28.2735 +    public void setMinimumFractionDigits(int newValue) {
 28.2736 +        minimumFractionDigits = Math.min(Math.max(0, newValue), MAXIMUM_FRACTION_DIGITS);
 28.2737 +        super.setMinimumFractionDigits((minimumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
 28.2738 +            DOUBLE_FRACTION_DIGITS : minimumFractionDigits);
 28.2739 +        if (minimumFractionDigits > maximumFractionDigits) {
 28.2740 +            maximumFractionDigits = minimumFractionDigits;
 28.2741 +            super.setMaximumFractionDigits((maximumFractionDigits > DOUBLE_FRACTION_DIGITS) ?
 28.2742 +                DOUBLE_FRACTION_DIGITS : maximumFractionDigits);
 28.2743 +        }
 28.2744 +    }
 28.2745 +
 28.2746 +    /**
 28.2747 +     * Gets the maximum number of digits allowed in the integer portion of a
 28.2748 +     * number.
 28.2749 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2750 +     * <code>BigDecimal</code> objects, the lower of the return value and
 28.2751 +     * 309 is used.
 28.2752 +     * @see #setMaximumIntegerDigits
 28.2753 +     */
 28.2754 +    public int getMaximumIntegerDigits() {
 28.2755 +        return maximumIntegerDigits;
 28.2756 +    }
 28.2757 +
 28.2758 +    /**
 28.2759 +     * Gets the minimum number of digits allowed in the integer portion of a
 28.2760 +     * number.
 28.2761 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2762 +     * <code>BigDecimal</code> objects, the lower of the return value and
 28.2763 +     * 309 is used.
 28.2764 +     * @see #setMinimumIntegerDigits
 28.2765 +     */
 28.2766 +    public int getMinimumIntegerDigits() {
 28.2767 +        return minimumIntegerDigits;
 28.2768 +    }
 28.2769 +
 28.2770 +    /**
 28.2771 +     * Gets the maximum number of digits allowed in the fraction portion of a
 28.2772 +     * number.
 28.2773 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2774 +     * <code>BigDecimal</code> objects, the lower of the return value and
 28.2775 +     * 340 is used.
 28.2776 +     * @see #setMaximumFractionDigits
 28.2777 +     */
 28.2778 +    public int getMaximumFractionDigits() {
 28.2779 +        return maximumFractionDigits;
 28.2780 +    }
 28.2781 +
 28.2782 +    /**
 28.2783 +     * Gets the minimum number of digits allowed in the fraction portion of a
 28.2784 +     * number.
 28.2785 +     * For formatting numbers other than <code>BigInteger</code> and
 28.2786 +     * <code>BigDecimal</code> objects, the lower of the return value and
 28.2787 +     * 340 is used.
 28.2788 +     * @see #setMinimumFractionDigits
 28.2789 +     */
 28.2790 +    public int getMinimumFractionDigits() {
 28.2791 +        return minimumFractionDigits;
 28.2792 +    }
 28.2793 +
 28.2794 +    /**
 28.2795 +     * Gets the currency used by this decimal format when formatting
 28.2796 +     * currency values.
 28.2797 +     * The currency is obtained by calling
 28.2798 +     * {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
 28.2799 +     * on this number format's symbols.
 28.2800 +     *
 28.2801 +     * @return the currency used by this decimal format, or <code>null</code>
 28.2802 +     * @since 1.4
 28.2803 +     */
 28.2804 +    public Currency getCurrency() {
 28.2805 +        return symbols.getCurrency();
 28.2806 +    }
 28.2807 +
 28.2808 +    /**
 28.2809 +     * Sets the currency used by this number format when formatting
 28.2810 +     * currency values. This does not update the minimum or maximum
 28.2811 +     * number of fraction digits used by the number format.
 28.2812 +     * The currency is set by calling
 28.2813 +     * {@link DecimalFormatSymbols#setCurrency DecimalFormatSymbols.setCurrency}
 28.2814 +     * on this number format's symbols.
 28.2815 +     *
 28.2816 +     * @param currency the new currency to be used by this decimal format
 28.2817 +     * @exception NullPointerException if <code>currency</code> is null
 28.2818 +     * @since 1.4
 28.2819 +     */
 28.2820 +    public void setCurrency(Currency currency) {
 28.2821 +        if (currency != symbols.getCurrency()) {
 28.2822 +            symbols.setCurrency(currency);
 28.2823 +            if (isCurrencyFormat) {
 28.2824 +                expandAffixes();
 28.2825 +            }
 28.2826 +        }
 28.2827 +    }
 28.2828 +
 28.2829 +    /**
 28.2830 +     * Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
 28.2831 +     *
 28.2832 +     * @return The <code>RoundingMode</code> used for this DecimalFormat.
 28.2833 +     * @see #setRoundingMode(RoundingMode)
 28.2834 +     * @since 1.6
 28.2835 +     */
 28.2836 +    public RoundingMode getRoundingMode() {
 28.2837 +        return roundingMode;
 28.2838 +    }
 28.2839 +
 28.2840 +    /**
 28.2841 +     * Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
 28.2842 +     *
 28.2843 +     * @param roundingMode The <code>RoundingMode</code> to be used
 28.2844 +     * @see #getRoundingMode()
 28.2845 +     * @exception NullPointerException if <code>roundingMode</code> is null.
 28.2846 +     * @since 1.6
 28.2847 +     */
 28.2848 +    public void setRoundingMode(RoundingMode roundingMode) {
 28.2849 +        if (roundingMode == null) {
 28.2850 +            throw new NullPointerException();
 28.2851 +        }
 28.2852 +
 28.2853 +        this.roundingMode = roundingMode;
 28.2854 +        digitList.setRoundingMode(roundingMode);
 28.2855 +    }
 28.2856 +
 28.2857 +    /**
 28.2858 +     * Adjusts the minimum and maximum fraction digits to values that
 28.2859 +     * are reasonable for the currency's default fraction digits.
 28.2860 +     */
 28.2861 +    void adjustForCurrencyDefaultFractionDigits() {
 28.2862 +        Currency currency = symbols.getCurrency();
 28.2863 +        if (currency == null) {
 28.2864 +            try {
 28.2865 +                currency = Currency.getInstance(symbols.getInternationalCurrencySymbol());
 28.2866 +            } catch (IllegalArgumentException e) {
 28.2867 +            }
 28.2868 +        }
 28.2869 +        if (currency != null) {
 28.2870 +            int digits = currency.getDefaultFractionDigits();
 28.2871 +            if (digits != -1) {
 28.2872 +                int oldMinDigits = getMinimumFractionDigits();
 28.2873 +                // Common patterns are "#.##", "#.00", "#".
 28.2874 +                // Try to adjust all of them in a reasonable way.
 28.2875 +                if (oldMinDigits == getMaximumFractionDigits()) {
 28.2876 +                    setMinimumFractionDigits(digits);
 28.2877 +                    setMaximumFractionDigits(digits);
 28.2878 +                } else {
 28.2879 +                    setMinimumFractionDigits(Math.min(digits, oldMinDigits));
 28.2880 +                    setMaximumFractionDigits(digits);
 28.2881 +                }
 28.2882 +            }
 28.2883 +        }
 28.2884 +    }
 28.2885 +
 28.2886 +    /**
 28.2887 +     * Reads the default serializable fields from the stream and performs
 28.2888 +     * validations and adjustments for older serialized versions. The
 28.2889 +     * validations and adjustments are:
 28.2890 +     * <ol>
 28.2891 +     * <li>
 28.2892 +     * Verify that the superclass's digit count fields correctly reflect
 28.2893 +     * the limits imposed on formatting numbers other than
 28.2894 +     * <code>BigInteger</code> and <code>BigDecimal</code> objects. These
 28.2895 +     * limits are stored in the superclass for serialization compatibility
 28.2896 +     * with older versions, while the limits for <code>BigInteger</code> and
 28.2897 +     * <code>BigDecimal</code> objects are kept in this class.
 28.2898 +     * If, in the superclass, the minimum or maximum integer digit count is
 28.2899 +     * larger than <code>DOUBLE_INTEGER_DIGITS</code> or if the minimum or
 28.2900 +     * maximum fraction digit count is larger than
 28.2901 +     * <code>DOUBLE_FRACTION_DIGITS</code>, then the stream data is invalid
 28.2902 +     * and this method throws an <code>InvalidObjectException</code>.
 28.2903 +     * <li>
 28.2904 +     * If <code>serialVersionOnStream</code> is less than 4, initialize
 28.2905 +     * <code>roundingMode</code> to {@link java.math.RoundingMode#HALF_EVEN
 28.2906 +     * RoundingMode.HALF_EVEN}.  This field is new with version 4.
 28.2907 +     * <li>
 28.2908 +     * If <code>serialVersionOnStream</code> is less than 3, then call
 28.2909 +     * the setters for the minimum and maximum integer and fraction digits with
 28.2910 +     * the values of the corresponding superclass getters to initialize the
 28.2911 +     * fields in this class. The fields in this class are new with version 3.
 28.2912 +     * <li>
 28.2913 +     * If <code>serialVersionOnStream</code> is less than 1, indicating that
 28.2914 +     * the stream was written by JDK 1.1, initialize
 28.2915 +     * <code>useExponentialNotation</code>
 28.2916 +     * to false, since it was not present in JDK 1.1.
 28.2917 +     * <li>
 28.2918 +     * Set <code>serialVersionOnStream</code> to the maximum allowed value so
 28.2919 +     * that default serialization will work properly if this object is streamed
 28.2920 +     * out again.
 28.2921 +     * </ol>
 28.2922 +     *
 28.2923 +     * <p>Stream versions older than 2 will not have the affix pattern variables
 28.2924 +     * <code>posPrefixPattern</code> etc.  As a result, they will be initialized
 28.2925 +     * to <code>null</code>, which means the affix strings will be taken as
 28.2926 +     * literal values.  This is exactly what we want, since that corresponds to
 28.2927 +     * the pre-version-2 behavior.
 28.2928 +     */
 28.2929 +    private void readObject(ObjectInputStream stream)
 28.2930 +         throws IOException, ClassNotFoundException
 28.2931 +    {
 28.2932 +        stream.defaultReadObject();
 28.2933 +        digitList = new DigitList();
 28.2934 +
 28.2935 +        if (serialVersionOnStream < 4) {
 28.2936 +            setRoundingMode(RoundingMode.HALF_EVEN);
 28.2937 +        }
 28.2938 +        // We only need to check the maximum counts because NumberFormat
 28.2939 +        // .readObject has already ensured that the maximum is greater than the
 28.2940 +        // minimum count.
 28.2941 +        if (super.getMaximumIntegerDigits() > DOUBLE_INTEGER_DIGITS ||
 28.2942 +            super.getMaximumFractionDigits() > DOUBLE_FRACTION_DIGITS) {
 28.2943 +            throw new InvalidObjectException("Digit count out of range");
 28.2944 +        }
 28.2945 +        if (serialVersionOnStream < 3) {
 28.2946 +            setMaximumIntegerDigits(super.getMaximumIntegerDigits());
 28.2947 +            setMinimumIntegerDigits(super.getMinimumIntegerDigits());
 28.2948 +            setMaximumFractionDigits(super.getMaximumFractionDigits());
 28.2949 +            setMinimumFractionDigits(super.getMinimumFractionDigits());
 28.2950 +        }
 28.2951 +        if (serialVersionOnStream < 1) {
 28.2952 +            // Didn't have exponential fields
 28.2953 +            useExponentialNotation = false;
 28.2954 +        }
 28.2955 +        serialVersionOnStream = currentSerialVersion;
 28.2956 +    }
 28.2957 +
 28.2958 +    //----------------------------------------------------------------------
 28.2959 +    // INSTANCE VARIABLES
 28.2960 +    //----------------------------------------------------------------------
 28.2961 +
 28.2962 +    private transient DigitList digitList = new DigitList();
 28.2963 +
 28.2964 +    /**
 28.2965 +     * The symbol used as a prefix when formatting positive numbers, e.g. "+".
 28.2966 +     *
 28.2967 +     * @serial
 28.2968 +     * @see #getPositivePrefix
 28.2969 +     */
 28.2970 +    private String  positivePrefix = "";
 28.2971 +
 28.2972 +    /**
 28.2973 +     * The symbol used as a suffix when formatting positive numbers.
 28.2974 +     * This is often an empty string.
 28.2975 +     *
 28.2976 +     * @serial
 28.2977 +     * @see #getPositiveSuffix
 28.2978 +     */
 28.2979 +    private String  positiveSuffix = "";
 28.2980 +
 28.2981 +    /**
 28.2982 +     * The symbol used as a prefix when formatting negative numbers, e.g. "-".
 28.2983 +     *
 28.2984 +     * @serial
 28.2985 +     * @see #getNegativePrefix
 28.2986 +     */
 28.2987 +    private String  negativePrefix = "-";
 28.2988 +
 28.2989 +    /**
 28.2990 +     * The symbol used as a suffix when formatting negative numbers.
 28.2991 +     * This is often an empty string.
 28.2992 +     *
 28.2993 +     * @serial
 28.2994 +     * @see #getNegativeSuffix
 28.2995 +     */
 28.2996 +    private String  negativeSuffix = "";
 28.2997 +
 28.2998 +    /**
 28.2999 +     * The prefix pattern for non-negative numbers.  This variable corresponds
 28.3000 +     * to <code>positivePrefix</code>.
 28.3001 +     *
 28.3002 +     * <p>This pattern is expanded by the method <code>expandAffix()</code> to
 28.3003 +     * <code>positivePrefix</code> to update the latter to reflect changes in
 28.3004 +     * <code>symbols</code>.  If this variable is <code>null</code> then
 28.3005 +     * <code>positivePrefix</code> is taken as a literal value that does not
 28.3006 +     * change when <code>symbols</code> changes.  This variable is always
 28.3007 +     * <code>null</code> for <code>DecimalFormat</code> objects older than
 28.3008 +     * stream version 2 restored from stream.
 28.3009 +     *
 28.3010 +     * @serial
 28.3011 +     * @since 1.3
 28.3012 +     */
 28.3013 +    private String posPrefixPattern;
 28.3014 +
 28.3015 +    /**
 28.3016 +     * The suffix pattern for non-negative numbers.  This variable corresponds
 28.3017 +     * to <code>positiveSuffix</code>.  This variable is analogous to
 28.3018 +     * <code>posPrefixPattern</code>; see that variable for further
 28.3019 +     * documentation.
 28.3020 +     *
 28.3021 +     * @serial
 28.3022 +     * @since 1.3
 28.3023 +     */
 28.3024 +    private String posSuffixPattern;
 28.3025 +
 28.3026 +    /**
 28.3027 +     * The prefix pattern for negative numbers.  This variable corresponds
 28.3028 +     * to <code>negativePrefix</code>.  This variable is analogous to
 28.3029 +     * <code>posPrefixPattern</code>; see that variable for further
 28.3030 +     * documentation.
 28.3031 +     *
 28.3032 +     * @serial
 28.3033 +     * @since 1.3
 28.3034 +     */
 28.3035 +    private String negPrefixPattern;
 28.3036 +
 28.3037 +    /**
 28.3038 +     * The suffix pattern for negative numbers.  This variable corresponds
 28.3039 +     * to <code>negativeSuffix</code>.  This variable is analogous to
 28.3040 +     * <code>posPrefixPattern</code>; see that variable for further
 28.3041 +     * documentation.
 28.3042 +     *
 28.3043 +     * @serial
 28.3044 +     * @since 1.3
 28.3045 +     */
 28.3046 +    private String negSuffixPattern;
 28.3047 +
 28.3048 +    /**
 28.3049 +     * The multiplier for use in percent, per mille, etc.
 28.3050 +     *
 28.3051 +     * @serial
 28.3052 +     * @see #getMultiplier
 28.3053 +     */
 28.3054 +    private int     multiplier = 1;
 28.3055 +
 28.3056 +    /**
 28.3057 +     * The number of digits between grouping separators in the integer
 28.3058 +     * portion of a number.  Must be greater than 0 if
 28.3059 +     * <code>NumberFormat.groupingUsed</code> is true.
 28.3060 +     *
 28.3061 +     * @serial
 28.3062 +     * @see #getGroupingSize
 28.3063 +     * @see java.text.NumberFormat#isGroupingUsed
 28.3064 +     */
 28.3065 +    private byte    groupingSize = 3;  // invariant, > 0 if useThousands
 28.3066 +
 28.3067 +    /**
 28.3068 +     * If true, forces the decimal separator to always appear in a formatted
 28.3069 +     * number, even if the fractional part of the number is zero.
 28.3070 +     *
 28.3071 +     * @serial
 28.3072 +     * @see #isDecimalSeparatorAlwaysShown
 28.3073 +     */
 28.3074 +    private boolean decimalSeparatorAlwaysShown = false;
 28.3075 +
 28.3076 +    /**
 28.3077 +     * If true, parse returns BigDecimal wherever possible.
 28.3078 +     *
 28.3079 +     * @serial
 28.3080 +     * @see #isParseBigDecimal
 28.3081 +     * @since 1.5
 28.3082 +     */
 28.3083 +    private boolean parseBigDecimal = false;
 28.3084 +
 28.3085 +
 28.3086 +    /**
 28.3087 +     * True if this object represents a currency format.  This determines
 28.3088 +     * whether the monetary decimal separator is used instead of the normal one.
 28.3089 +     */
 28.3090 +    private transient boolean isCurrencyFormat = false;
 28.3091 +
 28.3092 +    /**
 28.3093 +     * The <code>DecimalFormatSymbols</code> object used by this format.
 28.3094 +     * It contains the symbols used to format numbers, e.g. the grouping separator,
 28.3095 +     * decimal separator, and so on.
 28.3096 +     *
 28.3097 +     * @serial
 28.3098 +     * @see #setDecimalFormatSymbols
 28.3099 +     * @see java.text.DecimalFormatSymbols
 28.3100 +     */
 28.3101 +    private DecimalFormatSymbols symbols = null; // LIU new DecimalFormatSymbols();
 28.3102 +
 28.3103 +    /**
 28.3104 +     * True to force the use of exponential (i.e. scientific) notation when formatting
 28.3105 +     * numbers.
 28.3106 +     *
 28.3107 +     * @serial
 28.3108 +     * @since 1.2
 28.3109 +     */
 28.3110 +    private boolean useExponentialNotation;  // Newly persistent in the Java 2 platform v.1.2
 28.3111 +
 28.3112 +    /**
 28.3113 +     * FieldPositions describing the positive prefix String. This is
 28.3114 +     * lazily created. Use <code>getPositivePrefixFieldPositions</code>
 28.3115 +     * when needed.
 28.3116 +     */
 28.3117 +    private transient FieldPosition[] positivePrefixFieldPositions;
 28.3118 +
 28.3119 +    /**
 28.3120 +     * FieldPositions describing the positive suffix String. This is
 28.3121 +     * lazily created. Use <code>getPositiveSuffixFieldPositions</code>
 28.3122 +     * when needed.
 28.3123 +     */
 28.3124 +    private transient FieldPosition[] positiveSuffixFieldPositions;
 28.3125 +
 28.3126 +    /**
 28.3127 +     * FieldPositions describing the negative prefix String. This is
 28.3128 +     * lazily created. Use <code>getNegativePrefixFieldPositions</code>
 28.3129 +     * when needed.
 28.3130 +     */
 28.3131 +    private transient FieldPosition[] negativePrefixFieldPositions;
 28.3132 +
 28.3133 +    /**
 28.3134 +     * FieldPositions describing the negative suffix String. This is
 28.3135 +     * lazily created. Use <code>getNegativeSuffixFieldPositions</code>
 28.3136 +     * when needed.
 28.3137 +     */
 28.3138 +    private transient FieldPosition[] negativeSuffixFieldPositions;
 28.3139 +
 28.3140 +    /**
 28.3141 +     * The minimum number of digits used to display the exponent when a number is
 28.3142 +     * formatted in exponential notation.  This field is ignored if
 28.3143 +     * <code>useExponentialNotation</code> is not true.
 28.3144 +     *
 28.3145 +     * @serial
 28.3146 +     * @since 1.2
 28.3147 +     */
 28.3148 +    private byte    minExponentDigits;       // Newly persistent in the Java 2 platform v.1.2
 28.3149 +
 28.3150 +    /**
 28.3151 +     * The maximum number of digits allowed in the integer portion of a
 28.3152 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
 28.3153 +     * <code>maximumIntegerDigits</code> must be greater than or equal to
 28.3154 +     * <code>minimumIntegerDigits</code>.
 28.3155 +     *
 28.3156 +     * @serial
 28.3157 +     * @see #getMaximumIntegerDigits
 28.3158 +     * @since 1.5
 28.3159 +     */
 28.3160 +    private int    maximumIntegerDigits = super.getMaximumIntegerDigits();
 28.3161 +
 28.3162 +    /**
 28.3163 +     * The minimum number of digits allowed in the integer portion of a
 28.3164 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
 28.3165 +     * <code>minimumIntegerDigits</code> must be less than or equal to
 28.3166 +     * <code>maximumIntegerDigits</code>.
 28.3167 +     *
 28.3168 +     * @serial
 28.3169 +     * @see #getMinimumIntegerDigits
 28.3170 +     * @since 1.5
 28.3171 +     */
 28.3172 +    private int    minimumIntegerDigits = super.getMinimumIntegerDigits();
 28.3173 +
 28.3174 +    /**
 28.3175 +     * The maximum number of digits allowed in the fractional portion of a
 28.3176 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
 28.3177 +     * <code>maximumFractionDigits</code> must be greater than or equal to
 28.3178 +     * <code>minimumFractionDigits</code>.
 28.3179 +     *
 28.3180 +     * @serial
 28.3181 +     * @see #getMaximumFractionDigits
 28.3182 +     * @since 1.5
 28.3183 +     */
 28.3184 +    private int    maximumFractionDigits = super.getMaximumFractionDigits();
 28.3185 +
 28.3186 +    /**
 28.3187 +     * The minimum number of digits allowed in the fractional portion of a
 28.3188 +     * <code>BigInteger</code> or <code>BigDecimal</code> number.
 28.3189 +     * <code>minimumFractionDigits</code> must be less than or equal to
 28.3190 +     * <code>maximumFractionDigits</code>.
 28.3191 +     *
 28.3192 +     * @serial
 28.3193 +     * @see #getMinimumFractionDigits
 28.3194 +     * @since 1.5
 28.3195 +     */
 28.3196 +    private int    minimumFractionDigits = super.getMinimumFractionDigits();
 28.3197 +
 28.3198 +    /**
 28.3199 +     * The {@link java.math.RoundingMode} used in this DecimalFormat.
 28.3200 +     *
 28.3201 +     * @serial
 28.3202 +     * @since 1.6
 28.3203 +     */
 28.3204 +    private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
 28.3205 +
 28.3206 +    //----------------------------------------------------------------------
 28.3207 +
 28.3208 +    static final int currentSerialVersion = 4;
 28.3209 +
 28.3210 +    /**
 28.3211 +     * The internal serial version which says which version was written.
 28.3212 +     * Possible values are:
 28.3213 +     * <ul>
 28.3214 +     * <li><b>0</b> (default): versions before the Java 2 platform v1.2
 28.3215 +     * <li><b>1</b>: version for 1.2, which includes the two new fields
 28.3216 +     *      <code>useExponentialNotation</code> and
 28.3217 +     *      <code>minExponentDigits</code>.
 28.3218 +     * <li><b>2</b>: version for 1.3 and later, which adds four new fields:
 28.3219 +     *      <code>posPrefixPattern</code>, <code>posSuffixPattern</code>,
 28.3220 +     *      <code>negPrefixPattern</code>, and <code>negSuffixPattern</code>.
 28.3221 +     * <li><b>3</b>: version for 1.5 and later, which adds five new fields:
 28.3222 +     *      <code>maximumIntegerDigits</code>,
 28.3223 +     *      <code>minimumIntegerDigits</code>,
 28.3224 +     *      <code>maximumFractionDigits</code>,
 28.3225 +     *      <code>minimumFractionDigits</code>, and
 28.3226 +     *      <code>parseBigDecimal</code>.
 28.3227 +     * <li><b>4</b>: version for 1.6 and later, which adds one new field:
 28.3228 +     *      <code>roundingMode</code>.
 28.3229 +     * </ul>
 28.3230 +     * @since 1.2
 28.3231 +     * @serial
 28.3232 +     */
 28.3233 +    private int serialVersionOnStream = currentSerialVersion;
 28.3234 +
 28.3235 +    //----------------------------------------------------------------------
 28.3236 +    // CONSTANTS
 28.3237 +    //----------------------------------------------------------------------
 28.3238 +
 28.3239 +    // Constants for characters used in programmatic (unlocalized) patterns.
 28.3240 +    private static final char       PATTERN_ZERO_DIGIT         = '0';
 28.3241 +    private static final char       PATTERN_GROUPING_SEPARATOR = ',';
 28.3242 +    private static final char       PATTERN_DECIMAL_SEPARATOR  = '.';
 28.3243 +    private static final char       PATTERN_PER_MILLE          = '\u2030';
 28.3244 +    private static final char       PATTERN_PERCENT            = '%';
 28.3245 +    private static final char       PATTERN_DIGIT              = '#';
 28.3246 +    private static final char       PATTERN_SEPARATOR          = ';';
 28.3247 +    private static final String     PATTERN_EXPONENT           = "E";
 28.3248 +    private static final char       PATTERN_MINUS              = '-';
 28.3249 +
 28.3250 +    /**
 28.3251 +     * The CURRENCY_SIGN is the standard Unicode symbol for currency.  It
 28.3252 +     * is used in patterns and substituted with either the currency symbol,
 28.3253 +     * or if it is doubled, with the international currency symbol.  If the
 28.3254 +     * CURRENCY_SIGN is seen in a pattern, then the decimal separator is
 28.3255 +     * replaced with the monetary decimal separator.
 28.3256 +     *
 28.3257 +     * The CURRENCY_SIGN is not localized.
 28.3258 +     */
 28.3259 +    private static final char       CURRENCY_SIGN = '\u00A4';
 28.3260 +
 28.3261 +    private static final char       QUOTE = '\'';
 28.3262 +
 28.3263 +    private static FieldPosition[] EmptyFieldPositionArray = new FieldPosition[0];
 28.3264 +
 28.3265 +    // Upper limit on integer and fraction digits for a Java double
 28.3266 +    static final int DOUBLE_INTEGER_DIGITS  = 309;
 28.3267 +    static final int DOUBLE_FRACTION_DIGITS = 340;
 28.3268 +
 28.3269 +    // Upper limit on integer and fraction digits for BigDecimal and BigInteger
 28.3270 +    static final int MAXIMUM_INTEGER_DIGITS  = Integer.MAX_VALUE;
 28.3271 +    static final int MAXIMUM_FRACTION_DIGITS = Integer.MAX_VALUE;
 28.3272 +
 28.3273 +    // Proclaim JDK 1.1 serial compatibility.
 28.3274 +    static final long serialVersionUID = 864413376551465018L;
 28.3275 +
 28.3276 +    /**
 28.3277 +     * Cache to hold the NumberPattern of a Locale.
 28.3278 +     */
 28.3279 +    private static final ConcurrentMap<Locale, String> cachedLocaleData
 28.3280 +        = new ConcurrentHashMap<Locale, String>(3);
 28.3281 +}
    29.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    29.2 +++ b/rt/emul/compact/src/main/java/java/text/DecimalFormatSymbols.java	Thu Oct 03 15:40:35 2013 +0200
    29.3 @@ -0,0 +1,837 @@
    29.4 +/*
    29.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
    29.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    29.7 + *
    29.8 + * This code is free software; you can redistribute it and/or modify it
    29.9 + * under the terms of the GNU General Public License version 2 only, as
   29.10 + * published by the Free Software Foundation.  Oracle designates this
   29.11 + * particular file as subject to the "Classpath" exception as provided
   29.12 + * by Oracle in the LICENSE file that accompanied this code.
   29.13 + *
   29.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   29.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   29.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   29.17 + * version 2 for more details (a copy is included in the LICENSE file that
   29.18 + * accompanied this code).
   29.19 + *
   29.20 + * You should have received a copy of the GNU General Public License version
   29.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   29.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   29.23 + *
   29.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   29.25 + * or visit www.oracle.com if you need additional information or have any
   29.26 + * questions.
   29.27 + */
   29.28 +
   29.29 +/*
   29.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   29.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   29.32 + *
   29.33 + *   The original version of this source code and documentation is copyrighted
   29.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   29.35 + * materials are provided under terms of a License Agreement between Taligent
   29.36 + * and Sun. This technology is protected by multiple US and International
   29.37 + * patents. This notice and attribution to Taligent may not be removed.
   29.38 + *   Taligent is a registered trademark of Taligent, Inc.
   29.39 + *
   29.40 + */
   29.41 +
   29.42 +package java.text;
   29.43 +
   29.44 +import java.io.IOException;
   29.45 +import java.io.ObjectInputStream;
   29.46 +import java.io.Serializable;
   29.47 +import java.text.spi.DecimalFormatSymbolsProvider;
   29.48 +import java.util.Currency;
   29.49 +import java.util.Locale;
   29.50 +import java.util.ResourceBundle;
   29.51 +import java.util.concurrent.ConcurrentHashMap;
   29.52 +
   29.53 +import sun.util.LocaleServiceProviderPool;
   29.54 +import sun.util.resources.LocaleData;
   29.55 +
   29.56 +/**
   29.57 + * This class represents the set of symbols (such as the decimal separator,
   29.58 + * the grouping separator, and so on) needed by <code>DecimalFormat</code>
   29.59 + * to format numbers. <code>DecimalFormat</code> creates for itself an instance of
   29.60 + * <code>DecimalFormatSymbols</code> from its locale data.  If you need to change any
   29.61 + * of these symbols, you can get the <code>DecimalFormatSymbols</code> object from
   29.62 + * your <code>DecimalFormat</code> and modify it.
   29.63 + *
   29.64 + * @see          java.util.Locale
   29.65 + * @see          DecimalFormat
   29.66 + * @author       Mark Davis
   29.67 + * @author       Alan Liu
   29.68 + */
   29.69 +
   29.70 +public class DecimalFormatSymbols implements Cloneable, Serializable {
   29.71 +
   29.72 +    /**
   29.73 +     * Create a DecimalFormatSymbols object for the default locale.
   29.74 +     * This constructor can only construct instances for the locales
   29.75 +     * supported by the Java runtime environment, not for those
   29.76 +     * supported by installed
   29.77 +     * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
   29.78 +     * implementations. For full locale coverage, use the
   29.79 +     * {@link #getInstance(Locale) getInstance} method.
   29.80 +     */
   29.81 +    public DecimalFormatSymbols() {
   29.82 +        initialize( Locale.getDefault(Locale.Category.FORMAT) );
   29.83 +    }
   29.84 +
   29.85 +    /**
   29.86 +     * Create a DecimalFormatSymbols object for the given locale.
   29.87 +     * This constructor can only construct instances for the locales
   29.88 +     * supported by the Java runtime environment, not for those
   29.89 +     * supported by installed
   29.90 +     * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
   29.91 +     * implementations. For full locale coverage, use the
   29.92 +     * {@link #getInstance(Locale) getInstance} method.
   29.93 +     *
   29.94 +     * @exception NullPointerException if <code>locale</code> is null
   29.95 +     */
   29.96 +    public DecimalFormatSymbols( Locale locale ) {
   29.97 +        initialize( locale );
   29.98 +    }
   29.99 +
  29.100 +    /**
  29.101 +     * Returns an array of all locales for which the
  29.102 +     * <code>getInstance</code> methods of this class can return
  29.103 +     * localized instances.
  29.104 +     * The returned array represents the union of locales supported by the Java
  29.105 +     * runtime and by installed
  29.106 +     * {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
  29.107 +     * implementations.  It must contain at least a <code>Locale</code>
  29.108 +     * instance equal to {@link java.util.Locale#US Locale.US}.
  29.109 +     *
  29.110 +     * @return An array of locales for which localized
  29.111 +     *         <code>DecimalFormatSymbols</code> instances are available.
  29.112 +     * @since 1.6
  29.113 +     */
  29.114 +    public static Locale[] getAvailableLocales() {
  29.115 +        LocaleServiceProviderPool pool =
  29.116 +            LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
  29.117 +        return pool.getAvailableLocales();
  29.118 +    }
  29.119 +
  29.120 +    /**
  29.121 +     * Gets the <code>DecimalFormatSymbols</code> instance for the default
  29.122 +     * locale.  This method provides access to <code>DecimalFormatSymbols</code>
  29.123 +     * instances for locales supported by the Java runtime itself as well
  29.124 +     * as for those supported by installed
  29.125 +     * {@link java.text.spi.DecimalFormatSymbolsProvider
  29.126 +     * DecimalFormatSymbolsProvider} implementations.
  29.127 +     * @return a <code>DecimalFormatSymbols</code> instance.
  29.128 +     * @since 1.6
  29.129 +     */
  29.130 +    public static final DecimalFormatSymbols getInstance() {
  29.131 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT));
  29.132 +    }
  29.133 +
  29.134 +    /**
  29.135 +     * Gets the <code>DecimalFormatSymbols</code> instance for the specified
  29.136 +     * locale.  This method provides access to <code>DecimalFormatSymbols</code>
  29.137 +     * instances for locales supported by the Java runtime itself as well
  29.138 +     * as for those supported by installed
  29.139 +     * {@link java.text.spi.DecimalFormatSymbolsProvider
  29.140 +     * DecimalFormatSymbolsProvider} implementations.
  29.141 +     * @param locale the desired locale.
  29.142 +     * @return a <code>DecimalFormatSymbols</code> instance.
  29.143 +     * @exception NullPointerException if <code>locale</code> is null
  29.144 +     * @since 1.6
  29.145 +     */
  29.146 +    public static final DecimalFormatSymbols getInstance(Locale locale) {
  29.147 +
  29.148 +        // Check whether a provider can provide an implementation that's closer
  29.149 +        // to the requested locale than what the Java runtime itself can provide.
  29.150 +        LocaleServiceProviderPool pool =
  29.151 +            LocaleServiceProviderPool.getPool(DecimalFormatSymbolsProvider.class);
  29.152 +        if (pool.hasProviders()) {
  29.153 +            DecimalFormatSymbols providersInstance = pool.getLocalizedObject(
  29.154 +                                DecimalFormatSymbolsGetter.INSTANCE, locale);
  29.155 +            if (providersInstance != null) {
  29.156 +                return providersInstance;
  29.157 +            }
  29.158 +        }
  29.159 +
  29.160 +        return new DecimalFormatSymbols(locale);
  29.161 +    }
  29.162 +
  29.163 +    /**
  29.164 +     * Gets the character used for zero. Different for Arabic, etc.
  29.165 +     */
  29.166 +    public char getZeroDigit() {
  29.167 +        return zeroDigit;
  29.168 +    }
  29.169 +
  29.170 +    /**
  29.171 +     * Sets the character used for zero. Different for Arabic, etc.
  29.172 +     */
  29.173 +    public void setZeroDigit(char zeroDigit) {
  29.174 +        this.zeroDigit = zeroDigit;
  29.175 +    }
  29.176 +
  29.177 +    /**
  29.178 +     * Gets the character used for thousands separator. Different for French, etc.
  29.179 +     */
  29.180 +    public char getGroupingSeparator() {
  29.181 +        return groupingSeparator;
  29.182 +    }
  29.183 +
  29.184 +    /**
  29.185 +     * Sets the character used for thousands separator. Different for French, etc.
  29.186 +     */
  29.187 +    public void setGroupingSeparator(char groupingSeparator) {
  29.188 +        this.groupingSeparator = groupingSeparator;
  29.189 +    }
  29.190 +
  29.191 +    /**
  29.192 +     * Gets the character used for decimal sign. Different for French, etc.
  29.193 +     */
  29.194 +    public char getDecimalSeparator() {
  29.195 +        return decimalSeparator;
  29.196 +    }
  29.197 +
  29.198 +    /**
  29.199 +     * Sets the character used for decimal sign. Different for French, etc.
  29.200 +     */
  29.201 +    public void setDecimalSeparator(char decimalSeparator) {
  29.202 +        this.decimalSeparator = decimalSeparator;
  29.203 +    }
  29.204 +
  29.205 +    /**
  29.206 +     * Gets the character used for per mille sign. Different for Arabic, etc.
  29.207 +     */
  29.208 +    public char getPerMill() {
  29.209 +        return perMill;
  29.210 +    }
  29.211 +
  29.212 +    /**
  29.213 +     * Sets the character used for per mille sign. Different for Arabic, etc.
  29.214 +     */
  29.215 +    public void setPerMill(char perMill) {
  29.216 +        this.perMill = perMill;
  29.217 +    }
  29.218 +
  29.219 +    /**
  29.220 +     * Gets the character used for percent sign. Different for Arabic, etc.
  29.221 +     */
  29.222 +    public char getPercent() {
  29.223 +        return percent;
  29.224 +    }
  29.225 +
  29.226 +    /**
  29.227 +     * Sets the character used for percent sign. Different for Arabic, etc.
  29.228 +     */
  29.229 +    public void setPercent(char percent) {
  29.230 +        this.percent = percent;
  29.231 +    }
  29.232 +
  29.233 +    /**
  29.234 +     * Gets the character used for a digit in a pattern.
  29.235 +     */
  29.236 +    public char getDigit() {
  29.237 +        return digit;
  29.238 +    }
  29.239 +
  29.240 +    /**
  29.241 +     * Sets the character used for a digit in a pattern.
  29.242 +     */
  29.243 +    public void setDigit(char digit) {
  29.244 +        this.digit = digit;
  29.245 +    }
  29.246 +
  29.247 +    /**
  29.248 +     * Gets the character used to separate positive and negative subpatterns
  29.249 +     * in a pattern.
  29.250 +     */
  29.251 +    public char getPatternSeparator() {
  29.252 +        return patternSeparator;
  29.253 +    }
  29.254 +
  29.255 +    /**
  29.256 +     * Sets the character used to separate positive and negative subpatterns
  29.257 +     * in a pattern.
  29.258 +     */
  29.259 +    public void setPatternSeparator(char patternSeparator) {
  29.260 +        this.patternSeparator = patternSeparator;
  29.261 +    }
  29.262 +
  29.263 +    /**
  29.264 +     * Gets the string used to represent infinity. Almost always left
  29.265 +     * unchanged.
  29.266 +     */
  29.267 +    public String getInfinity() {
  29.268 +        return infinity;
  29.269 +    }
  29.270 +
  29.271 +    /**
  29.272 +     * Sets the string used to represent infinity. Almost always left
  29.273 +     * unchanged.
  29.274 +     */
  29.275 +    public void setInfinity(String infinity) {
  29.276 +        this.infinity = infinity;
  29.277 +    }
  29.278 +
  29.279 +    /**
  29.280 +     * Gets the string used to represent "not a number". Almost always left
  29.281 +     * unchanged.
  29.282 +     */
  29.283 +    public String getNaN() {
  29.284 +        return NaN;
  29.285 +    }
  29.286 +
  29.287 +    /**
  29.288 +     * Sets the string used to represent "not a number". Almost always left
  29.289 +     * unchanged.
  29.290 +     */
  29.291 +    public void setNaN(String NaN) {
  29.292 +        this.NaN = NaN;
  29.293 +    }
  29.294 +
  29.295 +    /**
  29.296 +     * Gets the character used to represent minus sign. If no explicit
  29.297 +     * negative format is specified, one is formed by prefixing
  29.298 +     * minusSign to the positive format.
  29.299 +     */
  29.300 +    public char getMinusSign() {
  29.301 +        return minusSign;
  29.302 +    }
  29.303 +
  29.304 +    /**
  29.305 +     * Sets the character used to represent minus sign. If no explicit
  29.306 +     * negative format is specified, one is formed by prefixing
  29.307 +     * minusSign to the positive format.
  29.308 +     */
  29.309 +    public void setMinusSign(char minusSign) {
  29.310 +        this.minusSign = minusSign;
  29.311 +    }
  29.312 +
  29.313 +    /**
  29.314 +     * Returns the currency symbol for the currency of these
  29.315 +     * DecimalFormatSymbols in their locale.
  29.316 +     * @since 1.2
  29.317 +     */
  29.318 +    public String getCurrencySymbol()
  29.319 +    {
  29.320 +        return currencySymbol;
  29.321 +    }
  29.322 +
  29.323 +    /**
  29.324 +     * Sets the currency symbol for the currency of these
  29.325 +     * DecimalFormatSymbols in their locale.
  29.326 +     * @since 1.2
  29.327 +     */
  29.328 +    public void setCurrencySymbol(String currency)
  29.329 +    {
  29.330 +        currencySymbol = currency;
  29.331 +    }
  29.332 +
  29.333 +    /**
  29.334 +     * Returns the ISO 4217 currency code of the currency of these
  29.335 +     * DecimalFormatSymbols.
  29.336 +     * @since 1.2
  29.337 +     */
  29.338 +    public String getInternationalCurrencySymbol()
  29.339 +    {
  29.340 +        return intlCurrencySymbol;
  29.341 +    }
  29.342 +
  29.343 +    /**
  29.344 +     * Sets the ISO 4217 currency code of the currency of these
  29.345 +     * DecimalFormatSymbols.
  29.346 +     * If the currency code is valid (as defined by
  29.347 +     * {@link java.util.Currency#getInstance(java.lang.String) Currency.getInstance}),
  29.348 +     * this also sets the currency attribute to the corresponding Currency
  29.349 +     * instance and the currency symbol attribute to the currency's symbol
  29.350 +     * in the DecimalFormatSymbols' locale. If the currency code is not valid,
  29.351 +     * then the currency attribute is set to null and the currency symbol
  29.352 +     * attribute is not modified.
  29.353 +     *
  29.354 +     * @see #setCurrency
  29.355 +     * @see #setCurrencySymbol
  29.356 +     * @since 1.2
  29.357 +     */
  29.358 +    public void setInternationalCurrencySymbol(String currencyCode)
  29.359 +    {
  29.360 +        intlCurrencySymbol = currencyCode;
  29.361 +        currency = null;
  29.362 +        if (currencyCode != null) {
  29.363 +            try {
  29.364 +                currency = Currency.getInstance(currencyCode);
  29.365 +                currencySymbol = currency.getSymbol();
  29.366 +            } catch (IllegalArgumentException e) {
  29.367 +            }
  29.368 +        }
  29.369 +    }
  29.370 +
  29.371 +    /**
  29.372 +     * Gets the currency of these DecimalFormatSymbols. May be null if the
  29.373 +     * currency symbol attribute was previously set to a value that's not
  29.374 +     * a valid ISO 4217 currency code.
  29.375 +     *
  29.376 +     * @return the currency used, or null
  29.377 +     * @since 1.4
  29.378 +     */
  29.379 +    public Currency getCurrency() {
  29.380 +        return currency;
  29.381 +    }
  29.382 +
  29.383 +    /**
  29.384 +     * Sets the currency of these DecimalFormatSymbols.
  29.385 +     * This also sets the currency symbol attribute to the currency's symbol
  29.386 +     * in the DecimalFormatSymbols' locale, and the international currency
  29.387 +     * symbol attribute to the currency's ISO 4217 currency code.
  29.388 +     *
  29.389 +     * @param currency the new currency to be used
  29.390 +     * @exception NullPointerException if <code>currency</code> is null
  29.391 +     * @since 1.4
  29.392 +     * @see #setCurrencySymbol
  29.393 +     * @see #setInternationalCurrencySymbol
  29.394 +     */
  29.395 +    public void setCurrency(Currency currency) {
  29.396 +        if (currency == null) {
  29.397 +            throw new NullPointerException();
  29.398 +        }
  29.399 +        this.currency = currency;
  29.400 +        intlCurrencySymbol = currency.getCurrencyCode();
  29.401 +        currencySymbol = currency.getSymbol(locale);
  29.402 +    }
  29.403 +
  29.404 +
  29.405 +    /**
  29.406 +     * Returns the monetary decimal separator.
  29.407 +     * @since 1.2
  29.408 +     */
  29.409 +    public char getMonetaryDecimalSeparator()
  29.410 +    {
  29.411 +        return monetarySeparator;
  29.412 +    }
  29.413 +
  29.414 +    /**
  29.415 +     * Sets the monetary decimal separator.
  29.416 +     * @since 1.2
  29.417 +     */
  29.418 +    public void setMonetaryDecimalSeparator(char sep)
  29.419 +    {
  29.420 +        monetarySeparator = sep;
  29.421 +    }
  29.422 +
  29.423 +    //------------------------------------------------------------
  29.424 +    // BEGIN   Package Private methods ... to be made public later
  29.425 +    //------------------------------------------------------------
  29.426 +
  29.427 +    /**
  29.428 +     * Returns the character used to separate the mantissa from the exponent.
  29.429 +     */
  29.430 +    char getExponentialSymbol()
  29.431 +    {
  29.432 +        return exponential;
  29.433 +    }
  29.434 +  /**
  29.435 +   * Returns the string used to separate the mantissa from the exponent.
  29.436 +   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
  29.437 +   *
  29.438 +   * @return the exponent separator string
  29.439 +   * @see #setExponentSeparator(java.lang.String)
  29.440 +   * @since 1.6
  29.441 +   */
  29.442 +    public String getExponentSeparator()
  29.443 +    {
  29.444 +        return exponentialSeparator;
  29.445 +    }
  29.446 +
  29.447 +    /**
  29.448 +     * Sets the character used to separate the mantissa from the exponent.
  29.449 +     */
  29.450 +    void setExponentialSymbol(char exp)
  29.451 +    {
  29.452 +        exponential = exp;
  29.453 +    }
  29.454 +
  29.455 +  /**
  29.456 +   * Sets the string used to separate the mantissa from the exponent.
  29.457 +   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
  29.458 +   *
  29.459 +   * @param exp the exponent separator string
  29.460 +   * @exception NullPointerException if <code>exp</code> is null
  29.461 +   * @see #getExponentSeparator()
  29.462 +   * @since 1.6
  29.463 +   */
  29.464 +    public void setExponentSeparator(String exp)
  29.465 +    {
  29.466 +        if (exp == null) {
  29.467 +            throw new NullPointerException();
  29.468 +        }
  29.469 +        exponentialSeparator = exp;
  29.470 +     }
  29.471 +
  29.472 +
  29.473 +    //------------------------------------------------------------
  29.474 +    // END     Package Private methods ... to be made public later
  29.475 +    //------------------------------------------------------------
  29.476 +
  29.477 +    /**
  29.478 +     * Standard override.
  29.479 +     */
  29.480 +    public Object clone() {
  29.481 +        try {
  29.482 +            return (DecimalFormatSymbols)super.clone();
  29.483 +            // other fields are bit-copied
  29.484 +        } catch (CloneNotSupportedException e) {
  29.485 +            throw new InternalError();
  29.486 +        }
  29.487 +    }
  29.488 +
  29.489 +    /**
  29.490 +     * Override equals.
  29.491 +     */
  29.492 +    public boolean equals(Object obj) {
  29.493 +        if (obj == null) return false;
  29.494 +        if (this == obj) return true;
  29.495 +        if (getClass() != obj.getClass()) return false;
  29.496 +        DecimalFormatSymbols other = (DecimalFormatSymbols) obj;
  29.497 +        return (zeroDigit == other.zeroDigit &&
  29.498 +        groupingSeparator == other.groupingSeparator &&
  29.499 +        decimalSeparator == other.decimalSeparator &&
  29.500 +        percent == other.percent &&
  29.501 +        perMill == other.perMill &&
  29.502 +        digit == other.digit &&
  29.503 +        minusSign == other.minusSign &&
  29.504 +        patternSeparator == other.patternSeparator &&
  29.505 +        infinity.equals(other.infinity) &&
  29.506 +        NaN.equals(other.NaN) &&
  29.507 +        currencySymbol.equals(other.currencySymbol) &&
  29.508 +        intlCurrencySymbol.equals(other.intlCurrencySymbol) &&
  29.509 +        currency == other.currency &&
  29.510 +        monetarySeparator == other.monetarySeparator &&
  29.511 +        exponentialSeparator.equals(other.exponentialSeparator) &&
  29.512 +        locale.equals(other.locale));
  29.513 +    }
  29.514 +
  29.515 +    /**
  29.516 +     * Override hashCode.
  29.517 +     */
  29.518 +    public int hashCode() {
  29.519 +            int result = zeroDigit;
  29.520 +            result = result * 37 + groupingSeparator;
  29.521 +            result = result * 37 + decimalSeparator;
  29.522 +            return result;
  29.523 +    }
  29.524 +
  29.525 +    /**
  29.526 +     * Initializes the symbols from the FormatData resource bundle.
  29.527 +     */
  29.528 +    private void initialize( Locale locale ) {
  29.529 +        this.locale = locale;
  29.530 +
  29.531 +        // get resource bundle data - try the cache first
  29.532 +        boolean needCacheUpdate = false;
  29.533 +        Object[] data = cachedLocaleData.get(locale);
  29.534 +        if (data == null) {  /* cache miss */
  29.535 +            // When numbering system is thai (Locale's extension contains u-nu-thai),
  29.536 +            // we read the data from th_TH_TH.
  29.537 +            Locale lookupLocale = locale;
  29.538 +            String numberType = locale.getUnicodeLocaleType("nu");
  29.539 +            if (numberType != null && numberType.equals("thai")) {
  29.540 +                lookupLocale = new Locale("th", "TH", "TH");
  29.541 +            }
  29.542 +            data = new Object[3];
  29.543 +            ResourceBundle rb = LocaleData.getNumberFormatData(lookupLocale);
  29.544 +            data[0] = rb.getStringArray("NumberElements");
  29.545 +            needCacheUpdate = true;
  29.546 +        }
  29.547 +
  29.548 +        String[] numberElements = (String[]) data[0];
  29.549 +
  29.550 +        decimalSeparator = numberElements[0].charAt(0);
  29.551 +        groupingSeparator = numberElements[1].charAt(0);
  29.552 +        patternSeparator = numberElements[2].charAt(0);
  29.553 +        percent = numberElements[3].charAt(0);
  29.554 +        zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
  29.555 +        digit = numberElements[5].charAt(0);
  29.556 +        minusSign = numberElements[6].charAt(0);
  29.557 +        exponential = numberElements[7].charAt(0);
  29.558 +        exponentialSeparator = numberElements[7]; //string representation new since 1.6
  29.559 +        perMill = numberElements[8].charAt(0);
  29.560 +        infinity  = numberElements[9];
  29.561 +        NaN = numberElements[10];
  29.562 +
  29.563 +        // Try to obtain the currency used in the locale's country.
  29.564 +        // Check for empty country string separately because it's a valid
  29.565 +        // country ID for Locale (and used for the C locale), but not a valid
  29.566 +        // ISO 3166 country code, and exceptions are expensive.
  29.567 +        if (!"".equals(locale.getCountry())) {
  29.568 +            try {
  29.569 +                currency = Currency.getInstance(locale);
  29.570 +            } catch (IllegalArgumentException e) {
  29.571 +                // use default values below for compatibility
  29.572 +            }
  29.573 +        }
  29.574 +        if (currency != null) {
  29.575 +            intlCurrencySymbol = currency.getCurrencyCode();
  29.576 +            if (data[1] != null && data[1] == intlCurrencySymbol) {
  29.577 +                currencySymbol = (String) data[2];
  29.578 +            } else {
  29.579 +                currencySymbol = currency.getSymbol(locale);
  29.580 +                data[1] = intlCurrencySymbol;
  29.581 +                data[2] = currencySymbol;
  29.582 +                needCacheUpdate = true;
  29.583 +            }
  29.584 +        } else {
  29.585 +            // default values
  29.586 +            intlCurrencySymbol = "XXX";
  29.587 +            try {
  29.588 +                currency = Currency.getInstance(intlCurrencySymbol);
  29.589 +            } catch (IllegalArgumentException e) {
  29.590 +            }
  29.591 +            currencySymbol = "\u00A4";
  29.592 +        }
  29.593 +        // Currently the monetary decimal separator is the same as the
  29.594 +        // standard decimal separator for all locales that we support.
  29.595 +        // If that changes, add a new entry to NumberElements.
  29.596 +        monetarySeparator = decimalSeparator;
  29.597 +
  29.598 +        if (needCacheUpdate) {
  29.599 +            cachedLocaleData.putIfAbsent(locale, data);
  29.600 +        }
  29.601 +    }
  29.602 +
  29.603 +    /**
  29.604 +     * Reads the default serializable fields, provides default values for objects
  29.605 +     * in older serial versions, and initializes non-serializable fields.
  29.606 +     * If <code>serialVersionOnStream</code>
  29.607 +     * is less than 1, initializes <code>monetarySeparator</code> to be
  29.608 +     * the same as <code>decimalSeparator</code> and <code>exponential</code>
  29.609 +     * to be 'E'.
  29.610 +     * If <code>serialVersionOnStream</code> is less than 2,
  29.611 +     * initializes <code>locale</code>to the root locale, and initializes
  29.612 +     * If <code>serialVersionOnStream</code> is less than 3, it initializes
  29.613 +     * <code>exponentialSeparator</code> using <code>exponential</code>.
  29.614 +     * Sets <code>serialVersionOnStream</code> back to the maximum allowed value so that
  29.615 +     * default serialization will work properly if this object is streamed out again.
  29.616 +     * Initializes the currency from the intlCurrencySymbol field.
  29.617 +     *
  29.618 +     * @since JDK 1.1.6
  29.619 +     */
  29.620 +    private void readObject(ObjectInputStream stream)
  29.621 +            throws IOException, ClassNotFoundException {
  29.622 +        stream.defaultReadObject();
  29.623 +        if (serialVersionOnStream < 1) {
  29.624 +            // Didn't have monetarySeparator or exponential field;
  29.625 +            // use defaults.
  29.626 +            monetarySeparator = decimalSeparator;
  29.627 +            exponential       = 'E';
  29.628 +        }
  29.629 +        if (serialVersionOnStream < 2) {
  29.630 +            // didn't have locale; use root locale
  29.631 +            locale = Locale.ROOT;
  29.632 +        }
  29.633 +        if (serialVersionOnStream < 3) {
  29.634 +            // didn't have exponentialSeparator. Create one using exponential
  29.635 +            exponentialSeparator = Character.toString(exponential);
  29.636 +        }
  29.637 +        serialVersionOnStream = currentSerialVersion;
  29.638 +
  29.639 +        if (intlCurrencySymbol != null) {
  29.640 +            try {
  29.641 +                 currency = Currency.getInstance(intlCurrencySymbol);
  29.642 +            } catch (IllegalArgumentException e) {
  29.643 +            }
  29.644 +        }
  29.645 +    }
  29.646 +
  29.647 +    /**
  29.648 +     * Character used for zero.
  29.649 +     *
  29.650 +     * @serial
  29.651 +     * @see #getZeroDigit
  29.652 +     */
  29.653 +    private  char    zeroDigit;
  29.654 +
  29.655 +    /**
  29.656 +     * Character used for thousands separator.
  29.657 +     *
  29.658 +     * @serial
  29.659 +     * @see #getGroupingSeparator
  29.660 +     */
  29.661 +    private  char    groupingSeparator;
  29.662 +
  29.663 +    /**
  29.664 +     * Character used for decimal sign.
  29.665 +     *
  29.666 +     * @serial
  29.667 +     * @see #getDecimalSeparator
  29.668 +     */
  29.669 +    private  char    decimalSeparator;
  29.670 +
  29.671 +    /**
  29.672 +     * Character used for per mille sign.
  29.673 +     *
  29.674 +     * @serial
  29.675 +     * @see #getPerMill
  29.676 +     */
  29.677 +    private  char    perMill;
  29.678 +
  29.679 +    /**
  29.680 +     * Character used for percent sign.
  29.681 +     * @serial
  29.682 +     * @see #getPercent
  29.683 +     */
  29.684 +    private  char    percent;
  29.685 +
  29.686 +    /**
  29.687 +     * Character used for a digit in a pattern.
  29.688 +     *
  29.689 +     * @serial
  29.690 +     * @see #getDigit
  29.691 +     */
  29.692 +    private  char    digit;
  29.693 +
  29.694 +    /**
  29.695 +     * Character used to separate positive and negative subpatterns
  29.696 +     * in a pattern.
  29.697 +     *
  29.698 +     * @serial
  29.699 +     * @see #getPatternSeparator
  29.700 +     */
  29.701 +    private  char    patternSeparator;
  29.702 +
  29.703 +    /**
  29.704 +     * String used to represent infinity.
  29.705 +     * @serial
  29.706 +     * @see #getInfinity
  29.707 +     */
  29.708 +    private  String  infinity;
  29.709 +
  29.710 +    /**
  29.711 +     * String used to represent "not a number".
  29.712 +     * @serial
  29.713 +     * @see #getNaN
  29.714 +     */
  29.715 +    private  String  NaN;
  29.716 +
  29.717 +    /**
  29.718 +     * Character used to represent minus sign.
  29.719 +     * @serial
  29.720 +     * @see #getMinusSign
  29.721 +     */
  29.722 +    private  char    minusSign;
  29.723 +
  29.724 +    /**
  29.725 +     * String denoting the local currency, e.g. "$".
  29.726 +     * @serial
  29.727 +     * @see #getCurrencySymbol
  29.728 +     */
  29.729 +    private  String  currencySymbol;
  29.730 +
  29.731 +    /**
  29.732 +     * ISO 4217 currency code denoting the local currency, e.g. "USD".
  29.733 +     * @serial
  29.734 +     * @see #getInternationalCurrencySymbol
  29.735 +     */
  29.736 +    private  String  intlCurrencySymbol;
  29.737 +
  29.738 +    /**
  29.739 +     * The decimal separator used when formatting currency values.
  29.740 +     * @serial
  29.741 +     * @since JDK 1.1.6
  29.742 +     * @see #getMonetaryDecimalSeparator
  29.743 +     */
  29.744 +    private  char    monetarySeparator; // Field new in JDK 1.1.6
  29.745 +
  29.746 +    /**
  29.747 +     * The character used to distinguish the exponent in a number formatted
  29.748 +     * in exponential notation, e.g. 'E' for a number such as "1.23E45".
  29.749 +     * <p>
  29.750 +     * Note that the public API provides no way to set this field,
  29.751 +     * even though it is supported by the implementation and the stream format.
  29.752 +     * The intent is that this will be added to the API in the future.
  29.753 +     *
  29.754 +     * @serial
  29.755 +     * @since JDK 1.1.6
  29.756 +     */
  29.757 +    private  char    exponential;       // Field new in JDK 1.1.6
  29.758 +
  29.759 +  /**
  29.760 +   * The string used to separate the mantissa from the exponent.
  29.761 +   * Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
  29.762 +   * <p>
  29.763 +   * If both <code>exponential</code> and <code>exponentialSeparator</code>
  29.764 +   * exist, this <code>exponentialSeparator</code> has the precedence.
  29.765 +   *
  29.766 +   * @serial
  29.767 +   * @since 1.6
  29.768 +   */
  29.769 +    private  String    exponentialSeparator;       // Field new in JDK 1.6
  29.770 +
  29.771 +    /**
  29.772 +     * The locale of these currency format symbols.
  29.773 +     *
  29.774 +     * @serial
  29.775 +     * @since 1.4
  29.776 +     */
  29.777 +    private Locale locale;
  29.778 +
  29.779 +    // currency; only the ISO code is serialized.
  29.780 +    private transient Currency currency;
  29.781 +
  29.782 +    // Proclaim JDK 1.1 FCS compatibility
  29.783 +    static final long serialVersionUID = 5772796243397350300L;
  29.784 +
  29.785 +    // The internal serial version which says which version was written
  29.786 +    // - 0 (default) for version up to JDK 1.1.5
  29.787 +    // - 1 for version from JDK 1.1.6, which includes two new fields:
  29.788 +    //     monetarySeparator and exponential.
  29.789 +    // - 2 for version from J2SE 1.4, which includes locale field.
  29.790 +    // - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
  29.791 +    private static final int currentSerialVersion = 3;
  29.792 +
  29.793 +    /**
  29.794 +     * Describes the version of <code>DecimalFormatSymbols</code> present on the stream.
  29.795 +     * Possible values are:
  29.796 +     * <ul>
  29.797 +     * <li><b>0</b> (or uninitialized): versions prior to JDK 1.1.6.
  29.798 +     *
  29.799 +     * <li><b>1</b>: Versions written by JDK 1.1.6 or later, which include
  29.800 +     *      two new fields: <code>monetarySeparator</code> and <code>exponential</code>.
  29.801 +     * <li><b>2</b>: Versions written by J2SE 1.4 or later, which include a
  29.802 +     *      new <code>locale</code> field.
  29.803 +     * <li><b>3</b>: Versions written by J2SE 1.6 or later, which include a
  29.804 +     *      new <code>exponentialSeparator</code> field.
  29.805 +     * </ul>
  29.806 +     * When streaming out a <code>DecimalFormatSymbols</code>, the most recent format
  29.807 +     * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
  29.808 +     * is always written.
  29.809 +     *
  29.810 +     * @serial
  29.811 +     * @since JDK 1.1.6
  29.812 +     */
  29.813 +    private int serialVersionOnStream = currentSerialVersion;
  29.814 +
  29.815 +    /**
  29.816 +     * cache to hold the NumberElements and the Currency
  29.817 +     * of a Locale.
  29.818 +     */
  29.819 +    private static final ConcurrentHashMap<Locale, Object[]> cachedLocaleData = new ConcurrentHashMap<Locale, Object[]>(3);
  29.820 +
  29.821 +    /**
  29.822 +     * Obtains a DecimalFormatSymbols instance from a DecimalFormatSymbolsProvider
  29.823 +     * implementation.
  29.824 +     */
  29.825 +    private static class DecimalFormatSymbolsGetter
  29.826 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<DecimalFormatSymbolsProvider,
  29.827 +                                                                   DecimalFormatSymbols> {
  29.828 +        private static final DecimalFormatSymbolsGetter INSTANCE =
  29.829 +            new DecimalFormatSymbolsGetter();
  29.830 +
  29.831 +        public DecimalFormatSymbols getObject(
  29.832 +                                DecimalFormatSymbolsProvider decimalFormatSymbolsProvider,
  29.833 +                                Locale locale,
  29.834 +                                String key,
  29.835 +                                Object... params) {
  29.836 +            assert params.length == 0;
  29.837 +            return decimalFormatSymbolsProvider.getInstance(locale);
  29.838 +        }
  29.839 +    }
  29.840 +}
    30.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    30.2 +++ b/rt/emul/compact/src/main/java/java/text/DigitList.java	Thu Oct 03 15:40:35 2013 +0200
    30.3 @@ -0,0 +1,715 @@
    30.4 +/*
    30.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
    30.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    30.7 + *
    30.8 + * This code is free software; you can redistribute it and/or modify it
    30.9 + * under the terms of the GNU General Public License version 2 only, as
   30.10 + * published by the Free Software Foundation.  Oracle designates this
   30.11 + * particular file as subject to the "Classpath" exception as provided
   30.12 + * by Oracle in the LICENSE file that accompanied this code.
   30.13 + *
   30.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   30.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   30.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   30.17 + * version 2 for more details (a copy is included in the LICENSE file that
   30.18 + * accompanied this code).
   30.19 + *
   30.20 + * You should have received a copy of the GNU General Public License version
   30.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   30.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   30.23 + *
   30.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   30.25 + * or visit www.oracle.com if you need additional information or have any
   30.26 + * questions.
   30.27 + */
   30.28 +
   30.29 +/*
   30.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   30.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   30.32 + *
   30.33 + *   The original version of this source code and documentation is copyrighted
   30.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   30.35 + * materials are provided under terms of a License Agreement between Taligent
   30.36 + * and Sun. This technology is protected by multiple US and International
   30.37 + * patents. This notice and attribution to Taligent may not be removed.
   30.38 + *   Taligent is a registered trademark of Taligent, Inc.
   30.39 + *
   30.40 + */
   30.41 +
   30.42 +package java.text;
   30.43 +
   30.44 +import java.math.BigDecimal;
   30.45 +import java.math.BigInteger;
   30.46 +import java.math.RoundingMode;
   30.47 +
   30.48 +/**
   30.49 + * Digit List. Private to DecimalFormat.
   30.50 + * Handles the transcoding
   30.51 + * between numeric values and strings of characters.  Only handles
   30.52 + * non-negative numbers.  The division of labor between DigitList and
   30.53 + * DecimalFormat is that DigitList handles the radix 10 representation
   30.54 + * issues; DecimalFormat handles the locale-specific issues such as
   30.55 + * positive/negative, grouping, decimal point, currency, and so on.
   30.56 + *
   30.57 + * A DigitList is really a representation of a floating point value.
   30.58 + * It may be an integer value; we assume that a double has sufficient
   30.59 + * precision to represent all digits of a long.
   30.60 + *
   30.61 + * The DigitList representation consists of a string of characters,
   30.62 + * which are the digits radix 10, from '0' to '9'.  It also has a radix
   30.63 + * 10 exponent associated with it.  The value represented by a DigitList
   30.64 + * object can be computed by mulitplying the fraction f, where 0 <= f < 1,
   30.65 + * derived by placing all the digits of the list to the right of the
   30.66 + * decimal point, by 10^exponent.
   30.67 + *
   30.68 + * @see  Locale
   30.69 + * @see  Format
   30.70 + * @see  NumberFormat
   30.71 + * @see  DecimalFormat
   30.72 + * @see  ChoiceFormat
   30.73 + * @see  MessageFormat
   30.74 + * @author       Mark Davis, Alan Liu
   30.75 + */
   30.76 +final class DigitList implements Cloneable {
   30.77 +    /**
   30.78 +     * The maximum number of significant digits in an IEEE 754 double, that
   30.79 +     * is, in a Java double.  This must not be increased, or garbage digits
   30.80 +     * will be generated, and should not be decreased, or accuracy will be lost.
   30.81 +     */
   30.82 +    public static final int MAX_COUNT = 19; // == Long.toString(Long.MAX_VALUE).length()
   30.83 +
   30.84 +    /**
   30.85 +     * These data members are intentionally public and can be set directly.
   30.86 +     *
   30.87 +     * The value represented is given by placing the decimal point before
   30.88 +     * digits[decimalAt].  If decimalAt is < 0, then leading zeros between
   30.89 +     * the decimal point and the first nonzero digit are implied.  If decimalAt
   30.90 +     * is > count, then trailing zeros between the digits[count-1] and the
   30.91 +     * decimal point are implied.
   30.92 +     *
   30.93 +     * Equivalently, the represented value is given by f * 10^decimalAt.  Here
   30.94 +     * f is a value 0.1 <= f < 1 arrived at by placing the digits in Digits to
   30.95 +     * the right of the decimal.
   30.96 +     *
   30.97 +     * DigitList is normalized, so if it is non-zero, figits[0] is non-zero.  We
   30.98 +     * don't allow denormalized numbers because our exponent is effectively of
   30.99 +     * unlimited magnitude.  The count value contains the number of significant
  30.100 +     * digits present in digits[].
  30.101 +     *
  30.102 +     * Zero is represented by any DigitList with count == 0 or with each digits[i]
  30.103 +     * for all i <= count == '0'.
  30.104 +     */
  30.105 +    public int decimalAt = 0;
  30.106 +    public int count = 0;
  30.107 +    public char[] digits = new char[MAX_COUNT];
  30.108 +
  30.109 +    private char[] data;
  30.110 +    private RoundingMode roundingMode = RoundingMode.HALF_EVEN;
  30.111 +    private boolean isNegative = false;
  30.112 +
  30.113 +    /**
  30.114 +     * Return true if the represented number is zero.
  30.115 +     */
  30.116 +    boolean isZero() {
  30.117 +        for (int i=0; i < count; ++i) {
  30.118 +            if (digits[i] != '0') {
  30.119 +                return false;
  30.120 +            }
  30.121 +        }
  30.122 +        return true;
  30.123 +    }
  30.124 +
  30.125 +    /**
  30.126 +     * Set the rounding mode
  30.127 +     */
  30.128 +    void setRoundingMode(RoundingMode r) {
  30.129 +        roundingMode = r;
  30.130 +    }
  30.131 +
  30.132 +    /**
  30.133 +     * Clears out the digits.
  30.134 +     * Use before appending them.
  30.135 +     * Typically, you set a series of digits with append, then at the point
  30.136 +     * you hit the decimal point, you set myDigitList.decimalAt = myDigitList.count;
  30.137 +     * then go on appending digits.
  30.138 +     */
  30.139 +    public void clear () {
  30.140 +        decimalAt = 0;
  30.141 +        count = 0;
  30.142 +    }
  30.143 +
  30.144 +    /**
  30.145 +     * Appends a digit to the list, extending the list when necessary.
  30.146 +     */
  30.147 +    public void append(char digit) {
  30.148 +        if (count == digits.length) {
  30.149 +            char[] data = new char[count + 100];
  30.150 +            System.arraycopy(digits, 0, data, 0, count);
  30.151 +            digits = data;
  30.152 +        }
  30.153 +        digits[count++] = digit;
  30.154 +    }
  30.155 +
  30.156 +    /**
  30.157 +     * Utility routine to get the value of the digit list
  30.158 +     * If (count == 0) this throws a NumberFormatException, which
  30.159 +     * mimics Long.parseLong().
  30.160 +     */
  30.161 +    public final double getDouble() {
  30.162 +        if (count == 0) {
  30.163 +            return 0.0;
  30.164 +        }
  30.165 +
  30.166 +        StringBuffer temp = getStringBuffer();
  30.167 +        temp.append('.');
  30.168 +        temp.append(digits, 0, count);
  30.169 +        temp.append('E');
  30.170 +        temp.append(decimalAt);
  30.171 +        return Double.parseDouble(temp.toString());
  30.172 +    }
  30.173 +
  30.174 +    /**
  30.175 +     * Utility routine to get the value of the digit list.
  30.176 +     * If (count == 0) this returns 0, unlike Long.parseLong().
  30.177 +     */
  30.178 +    public final long getLong() {
  30.179 +        // for now, simple implementation; later, do proper IEEE native stuff
  30.180 +
  30.181 +        if (count == 0) {
  30.182 +            return 0;
  30.183 +        }
  30.184 +
  30.185 +        // We have to check for this, because this is the one NEGATIVE value
  30.186 +        // we represent.  If we tried to just pass the digits off to parseLong,
  30.187 +        // we'd get a parse failure.
  30.188 +        if (isLongMIN_VALUE()) {
  30.189 +            return Long.MIN_VALUE;
  30.190 +        }
  30.191 +
  30.192 +        StringBuffer temp = getStringBuffer();
  30.193 +        temp.append(digits, 0, count);
  30.194 +        for (int i = count; i < decimalAt; ++i) {
  30.195 +            temp.append('0');
  30.196 +        }
  30.197 +        return Long.parseLong(temp.toString());
  30.198 +    }
  30.199 +
  30.200 +    public final BigDecimal getBigDecimal() {
  30.201 +        if (count == 0) {
  30.202 +            if (decimalAt == 0) {
  30.203 +                return BigDecimal.ZERO;
  30.204 +            } else {
  30.205 +                return new BigDecimal("0E" + decimalAt);
  30.206 +            }
  30.207 +        }
  30.208 +
  30.209 +       if (decimalAt == count) {
  30.210 +           return new BigDecimal(digits, 0, count);
  30.211 +       } else {
  30.212 +           return new BigDecimal(digits, 0, count).scaleByPowerOfTen(decimalAt - count);
  30.213 +       }
  30.214 +    }
  30.215 +
  30.216 +    /**
  30.217 +     * Return true if the number represented by this object can fit into
  30.218 +     * a long.
  30.219 +     * @param isPositive true if this number should be regarded as positive
  30.220 +     * @param ignoreNegativeZero true if -0 should be regarded as identical to
  30.221 +     * +0; otherwise they are considered distinct
  30.222 +     * @return true if this number fits into a Java long
  30.223 +     */
  30.224 +    boolean fitsIntoLong(boolean isPositive, boolean ignoreNegativeZero) {
  30.225 +        // Figure out if the result will fit in a long.  We have to
  30.226 +        // first look for nonzero digits after the decimal point;
  30.227 +        // then check the size.  If the digit count is 18 or less, then
  30.228 +        // the value can definitely be represented as a long.  If it is 19
  30.229 +        // then it may be too large.
  30.230 +
  30.231 +        // Trim trailing zeros.  This does not change the represented value.
  30.232 +        while (count > 0 && digits[count - 1] == '0') {
  30.233 +            --count;
  30.234 +        }
  30.235 +
  30.236 +        if (count == 0) {
  30.237 +            // Positive zero fits into a long, but negative zero can only
  30.238 +            // be represented as a double. - bug 4162852
  30.239 +            return isPositive || ignoreNegativeZero;
  30.240 +        }
  30.241 +
  30.242 +        if (decimalAt < count || decimalAt > MAX_COUNT) {
  30.243 +            return false;
  30.244 +        }
  30.245 +
  30.246 +        if (decimalAt < MAX_COUNT) return true;
  30.247 +
  30.248 +        // At this point we have decimalAt == count, and count == MAX_COUNT.
  30.249 +        // The number will overflow if it is larger than 9223372036854775807
  30.250 +        // or smaller than -9223372036854775808.
  30.251 +        for (int i=0; i<count; ++i) {
  30.252 +            char dig = digits[i], max = LONG_MIN_REP[i];
  30.253 +            if (dig > max) return false;
  30.254 +            if (dig < max) return true;
  30.255 +        }
  30.256 +
  30.257 +        // At this point the first count digits match.  If decimalAt is less
  30.258 +        // than count, then the remaining digits are zero, and we return true.
  30.259 +        if (count < decimalAt) return true;
  30.260 +
  30.261 +        // Now we have a representation of Long.MIN_VALUE, without the leading
  30.262 +        // negative sign.  If this represents a positive value, then it does
  30.263 +        // not fit; otherwise it fits.
  30.264 +        return !isPositive;
  30.265 +    }
  30.266 +
  30.267 +    /**
  30.268 +     * Set the digit list to a representation of the given double value.
  30.269 +     * This method supports fixed-point notation.
  30.270 +     * @param isNegative Boolean value indicating whether the number is negative.
  30.271 +     * @param source Value to be converted; must not be Inf, -Inf, Nan,
  30.272 +     * or a value <= 0.
  30.273 +     * @param maximumFractionDigits The most fractional digits which should
  30.274 +     * be converted.
  30.275 +     */
  30.276 +    public final void set(boolean isNegative, double source, int maximumFractionDigits) {
  30.277 +        set(isNegative, source, maximumFractionDigits, true);
  30.278 +    }
  30.279 +
  30.280 +    /**
  30.281 +     * Set the digit list to a representation of the given double value.
  30.282 +     * This method supports both fixed-point and exponential notation.
  30.283 +     * @param isNegative Boolean value indicating whether the number is negative.
  30.284 +     * @param source Value to be converted; must not be Inf, -Inf, Nan,
  30.285 +     * or a value <= 0.
  30.286 +     * @param maximumDigits The most fractional or total digits which should
  30.287 +     * be converted.
  30.288 +     * @param fixedPoint If true, then maximumDigits is the maximum
  30.289 +     * fractional digits to be converted.  If false, total digits.
  30.290 +     */
  30.291 +    final void set(boolean isNegative, double source, int maximumDigits, boolean fixedPoint) {
  30.292 +        set(isNegative, Double.toString(source), maximumDigits, fixedPoint);
  30.293 +    }
  30.294 +
  30.295 +    /**
  30.296 +     * Generate a representation of the form DDDDD, DDDDD.DDDDD, or
  30.297 +     * DDDDDE+/-DDDDD.
  30.298 +     */
  30.299 +    final void set(boolean isNegative, String s, int maximumDigits, boolean fixedPoint) {
  30.300 +        this.isNegative = isNegative;
  30.301 +        int len = s.length();
  30.302 +        char[] source = getDataChars(len);
  30.303 +        s.getChars(0, len, source, 0);
  30.304 +
  30.305 +        decimalAt = -1;
  30.306 +        count = 0;
  30.307 +        int exponent = 0;
  30.308 +        // Number of zeros between decimal point and first non-zero digit after
  30.309 +        // decimal point, for numbers < 1.
  30.310 +        int leadingZerosAfterDecimal = 0;
  30.311 +        boolean nonZeroDigitSeen = false;
  30.312 +
  30.313 +        for (int i = 0; i < len; ) {
  30.314 +            char c = source[i++];
  30.315 +            if (c == '.') {
  30.316 +                decimalAt = count;
  30.317 +            } else if (c == 'e' || c == 'E') {
  30.318 +                exponent = parseInt(source, i, len);
  30.319 +                break;
  30.320 +            } else {
  30.321 +                if (!nonZeroDigitSeen) {
  30.322 +                    nonZeroDigitSeen = (c != '0');
  30.323 +                    if (!nonZeroDigitSeen && decimalAt != -1)
  30.324 +                        ++leadingZerosAfterDecimal;
  30.325 +                }
  30.326 +                if (nonZeroDigitSeen) {
  30.327 +                    digits[count++] = c;
  30.328 +                }
  30.329 +            }
  30.330 +        }
  30.331 +        if (decimalAt == -1) {
  30.332 +            decimalAt = count;
  30.333 +        }
  30.334 +        if (nonZeroDigitSeen) {
  30.335 +            decimalAt += exponent - leadingZerosAfterDecimal;
  30.336 +        }
  30.337 +
  30.338 +        if (fixedPoint) {
  30.339 +            // The negative of the exponent represents the number of leading
  30.340 +            // zeros between the decimal and the first non-zero digit, for
  30.341 +            // a value < 0.1 (e.g., for 0.00123, -decimalAt == 2).  If this
  30.342 +            // is more than the maximum fraction digits, then we have an underflow
  30.343 +            // for the printed representation.
  30.344 +            if (-decimalAt > maximumDigits) {
  30.345 +                // Handle an underflow to zero when we round something like
  30.346 +                // 0.0009 to 2 fractional digits.
  30.347 +                count = 0;
  30.348 +                return;
  30.349 +            } else if (-decimalAt == maximumDigits) {
  30.350 +                // If we round 0.0009 to 3 fractional digits, then we have to
  30.351 +                // create a new one digit in the least significant location.
  30.352 +                if (shouldRoundUp(0)) {
  30.353 +                    count = 1;
  30.354 +                    ++decimalAt;
  30.355 +                    digits[0] = '1';
  30.356 +                } else {
  30.357 +                    count = 0;
  30.358 +                }
  30.359 +                return;
  30.360 +            }
  30.361 +            // else fall through
  30.362 +        }
  30.363 +
  30.364 +        // Eliminate trailing zeros.
  30.365 +        while (count > 1 && digits[count - 1] == '0') {
  30.366 +            --count;
  30.367 +        }
  30.368 +
  30.369 +        // Eliminate digits beyond maximum digits to be displayed.
  30.370 +        // Round up if appropriate.
  30.371 +        round(fixedPoint ? (maximumDigits + decimalAt) : maximumDigits);
  30.372 +    }
  30.373 +
  30.374 +    /**
  30.375 +     * Round the representation to the given number of digits.
  30.376 +     * @param maximumDigits The maximum number of digits to be shown.
  30.377 +     * Upon return, count will be less than or equal to maximumDigits.
  30.378 +     */
  30.379 +    private final void round(int maximumDigits) {
  30.380 +        // Eliminate digits beyond maximum digits to be displayed.
  30.381 +        // Round up if appropriate.
  30.382 +        if (maximumDigits >= 0 && maximumDigits < count) {
  30.383 +            if (shouldRoundUp(maximumDigits)) {
  30.384 +                // Rounding up involved incrementing digits from LSD to MSD.
  30.385 +                // In most cases this is simple, but in a worst case situation
  30.386 +                // (9999..99) we have to adjust the decimalAt value.
  30.387 +                for (;;) {
  30.388 +                    --maximumDigits;
  30.389 +                    if (maximumDigits < 0) {
  30.390 +                        // We have all 9's, so we increment to a single digit
  30.391 +                        // of one and adjust the exponent.
  30.392 +                        digits[0] = '1';
  30.393 +                        ++decimalAt;
  30.394 +                        maximumDigits = 0; // Adjust the count
  30.395 +                        break;
  30.396 +                    }
  30.397 +
  30.398 +                    ++digits[maximumDigits];
  30.399 +                    if (digits[maximumDigits] <= '9') break;
  30.400 +                    // digits[maximumDigits] = '0'; // Unnecessary since we'll truncate this
  30.401 +                }
  30.402 +                ++maximumDigits; // Increment for use as count
  30.403 +            }
  30.404 +            count = maximumDigits;
  30.405 +
  30.406 +            // Eliminate trailing zeros.
  30.407 +            while (count > 1 && digits[count-1] == '0') {
  30.408 +                --count;
  30.409 +            }
  30.410 +        }
  30.411 +    }
  30.412 +
  30.413 +
  30.414 +    /**
  30.415 +     * Return true if truncating the representation to the given number
  30.416 +     * of digits will result in an increment to the last digit.  This
  30.417 +     * method implements the rounding modes defined in the
  30.418 +     * java.math.RoundingMode class.
  30.419 +     * [bnf]
  30.420 +     * @param maximumDigits the number of digits to keep, from 0 to
  30.421 +     * <code>count-1</code>.  If 0, then all digits are rounded away, and
  30.422 +     * this method returns true if a one should be generated (e.g., formatting
  30.423 +     * 0.09 with "#.#").
  30.424 +     * @exception ArithmeticException if rounding is needed with rounding
  30.425 +     *            mode being set to RoundingMode.UNNECESSARY
  30.426 +     * @return true if digit <code>maximumDigits-1</code> should be
  30.427 +     * incremented
  30.428 +     */
  30.429 +    private boolean shouldRoundUp(int maximumDigits) {
  30.430 +        if (maximumDigits < count) {
  30.431 +            switch(roundingMode) {
  30.432 +            case UP:
  30.433 +                for (int i=maximumDigits; i<count; ++i) {
  30.434 +                    if (digits[i] != '0') {
  30.435 +                        return true;
  30.436 +                    }
  30.437 +                }
  30.438 +                break;
  30.439 +            case DOWN:
  30.440 +                break;
  30.441 +            case CEILING:
  30.442 +                for (int i=maximumDigits; i<count; ++i) {
  30.443 +                    if (digits[i] != '0') {
  30.444 +                        return !isNegative;
  30.445 +                    }
  30.446 +                }
  30.447 +                break;
  30.448 +            case FLOOR:
  30.449 +                for (int i=maximumDigits; i<count; ++i) {
  30.450 +                    if (digits[i] != '0') {
  30.451 +                        return isNegative;
  30.452 +                    }
  30.453 +                }
  30.454 +                break;
  30.455 +            case HALF_UP:
  30.456 +                if (digits[maximumDigits] >= '5') {
  30.457 +                    return true;
  30.458 +                }
  30.459 +                break;
  30.460 +            case HALF_DOWN:
  30.461 +                if (digits[maximumDigits] > '5') {
  30.462 +                    return true;
  30.463 +                } else if (digits[maximumDigits] == '5' ) {
  30.464 +                    for (int i=maximumDigits+1; i<count; ++i) {
  30.465 +                        if (digits[i] != '0') {
  30.466 +                            return true;
  30.467 +                        }
  30.468 +                    }
  30.469 +                }
  30.470 +                break;
  30.471 +            case HALF_EVEN:
  30.472 +                // Implement IEEE half-even rounding
  30.473 +                if (digits[maximumDigits] > '5') {
  30.474 +                    return true;
  30.475 +                } else if (digits[maximumDigits] == '5' ) {
  30.476 +                    for (int i=maximumDigits+1; i<count; ++i) {
  30.477 +                        if (digits[i] != '0') {
  30.478 +                            return true;
  30.479 +                        }
  30.480 +                    }
  30.481 +                    return maximumDigits > 0 && (digits[maximumDigits-1] % 2 != 0);
  30.482 +                }
  30.483 +                break;
  30.484 +            case UNNECESSARY:
  30.485 +                for (int i=maximumDigits; i<count; ++i) {
  30.486 +                    if (digits[i] != '0') {
  30.487 +                        throw new ArithmeticException(
  30.488 +                            "Rounding needed with the rounding mode being set to RoundingMode.UNNECESSARY");
  30.489 +                    }
  30.490 +                }
  30.491 +                break;
  30.492 +            default:
  30.493 +                assert false;
  30.494 +            }
  30.495 +        }
  30.496 +        return false;
  30.497 +    }
  30.498 +
  30.499 +    /**
  30.500 +     * Utility routine to set the value of the digit list from a long
  30.501 +     */
  30.502 +    public final void set(boolean isNegative, long source) {
  30.503 +        set(isNegative, source, 0);
  30.504 +    }
  30.505 +
  30.506 +    /**
  30.507 +     * Set the digit list to a representation of the given long value.
  30.508 +     * @param isNegative Boolean value indicating whether the number is negative.
  30.509 +     * @param source Value to be converted; must be >= 0 or ==
  30.510 +     * Long.MIN_VALUE.
  30.511 +     * @param maximumDigits The most digits which should be converted.
  30.512 +     * If maximumDigits is lower than the number of significant digits
  30.513 +     * in source, the representation will be rounded.  Ignored if <= 0.
  30.514 +     */
  30.515 +    public final void set(boolean isNegative, long source, int maximumDigits) {
  30.516 +        this.isNegative = isNegative;
  30.517 +
  30.518 +        // This method does not expect a negative number. However,
  30.519 +        // "source" can be a Long.MIN_VALUE (-9223372036854775808),
  30.520 +        // if the number being formatted is a Long.MIN_VALUE.  In that
  30.521 +        // case, it will be formatted as -Long.MIN_VALUE, a number
  30.522 +        // which is outside the legal range of a long, but which can
  30.523 +        // be represented by DigitList.
  30.524 +        if (source <= 0) {
  30.525 +            if (source == Long.MIN_VALUE) {
  30.526 +                decimalAt = count = MAX_COUNT;
  30.527 +                System.arraycopy(LONG_MIN_REP, 0, digits, 0, count);
  30.528 +            } else {
  30.529 +                decimalAt = count = 0; // Values <= 0 format as zero
  30.530 +            }
  30.531 +        } else {
  30.532 +            // Rewritten to improve performance.  I used to call
  30.533 +            // Long.toString(), which was about 4x slower than this code.
  30.534 +            int left = MAX_COUNT;
  30.535 +            int right;
  30.536 +            while (source > 0) {
  30.537 +                digits[--left] = (char)('0' + (source % 10));
  30.538 +                source /= 10;
  30.539 +            }
  30.540 +            decimalAt = MAX_COUNT - left;
  30.541 +            // Don't copy trailing zeros.  We are guaranteed that there is at
  30.542 +            // least one non-zero digit, so we don't have to check lower bounds.
  30.543 +            for (right = MAX_COUNT - 1; digits[right] == '0'; --right)
  30.544 +                ;
  30.545 +            count = right - left + 1;
  30.546 +            System.arraycopy(digits, left, digits, 0, count);
  30.547 +        }
  30.548 +        if (maximumDigits > 0) round(maximumDigits);
  30.549 +    }
  30.550 +
  30.551 +    /**
  30.552 +     * Set the digit list to a representation of the given BigDecimal value.
  30.553 +     * This method supports both fixed-point and exponential notation.
  30.554 +     * @param isNegative Boolean value indicating whether the number is negative.
  30.555 +     * @param source Value to be converted; must not be a value <= 0.
  30.556 +     * @param maximumDigits The most fractional or total digits which should
  30.557 +     * be converted.
  30.558 +     * @param fixedPoint If true, then maximumDigits is the maximum
  30.559 +     * fractional digits to be converted.  If false, total digits.
  30.560 +     */
  30.561 +    final void set(boolean isNegative, BigDecimal source, int maximumDigits, boolean fixedPoint) {
  30.562 +        String s = source.toString();
  30.563 +        extendDigits(s.length());
  30.564 +
  30.565 +        set(isNegative, s, maximumDigits, fixedPoint);
  30.566 +    }
  30.567 +
  30.568 +    /**
  30.569 +     * Set the digit list to a representation of the given BigInteger value.
  30.570 +     * @param isNegative Boolean value indicating whether the number is negative.
  30.571 +     * @param source Value to be converted; must be >= 0.
  30.572 +     * @param maximumDigits The most digits which should be converted.
  30.573 +     * If maximumDigits is lower than the number of significant digits
  30.574 +     * in source, the representation will be rounded.  Ignored if <= 0.
  30.575 +     */
  30.576 +    final void set(boolean isNegative, BigInteger source, int maximumDigits) {
  30.577 +        this.isNegative = isNegative;
  30.578 +        String s = source.toString();
  30.579 +        int len = s.length();
  30.580 +        extendDigits(len);
  30.581 +        s.getChars(0, len, digits, 0);
  30.582 +
  30.583 +        decimalAt = len;
  30.584 +        int right;
  30.585 +        for (right = len - 1; right >= 0 && digits[right] == '0'; --right)
  30.586 +            ;
  30.587 +        count = right + 1;
  30.588 +
  30.589 +        if (maximumDigits > 0) {
  30.590 +            round(maximumDigits);
  30.591 +        }
  30.592 +    }
  30.593 +
  30.594 +    /**
  30.595 +     * equality test between two digit lists.
  30.596 +     */
  30.597 +    public boolean equals(Object obj) {
  30.598 +        if (this == obj)                      // quick check
  30.599 +            return true;
  30.600 +        if (!(obj instanceof DigitList))         // (1) same object?
  30.601 +            return false;
  30.602 +        DigitList other = (DigitList) obj;
  30.603 +        if (count != other.count ||
  30.604 +        decimalAt != other.decimalAt)
  30.605 +            return false;
  30.606 +        for (int i = 0; i < count; i++)
  30.607 +            if (digits[i] != other.digits[i])
  30.608 +                return false;
  30.609 +        return true;
  30.610 +    }
  30.611 +
  30.612 +    /**
  30.613 +     * Generates the hash code for the digit list.
  30.614 +     */
  30.615 +    public int hashCode() {
  30.616 +        int hashcode = decimalAt;
  30.617 +
  30.618 +        for (int i = 0; i < count; i++) {
  30.619 +            hashcode = hashcode * 37 + digits[i];
  30.620 +        }
  30.621 +
  30.622 +        return hashcode;
  30.623 +    }
  30.624 +
  30.625 +    /**
  30.626 +     * Creates a copy of this object.
  30.627 +     * @return a clone of this instance.
  30.628 +     */
  30.629 +    public Object clone() {
  30.630 +        try {
  30.631 +            DigitList other = (DigitList) super.clone();
  30.632 +            char[] newDigits = new char[digits.length];
  30.633 +            System.arraycopy(digits, 0, newDigits, 0, digits.length);
  30.634 +            other.digits = newDigits;
  30.635 +            other.tempBuffer = null;
  30.636 +            return other;
  30.637 +        } catch (CloneNotSupportedException e) {
  30.638 +            throw new InternalError();
  30.639 +        }
  30.640 +    }
  30.641 +
  30.642 +    /**
  30.643 +     * Returns true if this DigitList represents Long.MIN_VALUE;
  30.644 +     * false, otherwise.  This is required so that getLong() works.
  30.645 +     */
  30.646 +    private boolean isLongMIN_VALUE() {
  30.647 +        if (decimalAt != count || count != MAX_COUNT) {
  30.648 +            return false;
  30.649 +        }
  30.650 +
  30.651 +        for (int i = 0; i < count; ++i) {
  30.652 +            if (digits[i] != LONG_MIN_REP[i]) return false;
  30.653 +        }
  30.654 +
  30.655 +        return true;
  30.656 +    }
  30.657 +
  30.658 +    private static final int parseInt(char[] str, int offset, int strLen) {
  30.659 +        char c;
  30.660 +        boolean positive = true;
  30.661 +        if ((c = str[offset]) == '-') {
  30.662 +            positive = false;
  30.663 +            offset++;
  30.664 +        } else if (c == '+') {
  30.665 +            offset++;
  30.666 +        }
  30.667 +
  30.668 +        int value = 0;
  30.669 +        while (offset < strLen) {
  30.670 +            c = str[offset++];
  30.671 +            if (c >= '0' && c <= '9') {
  30.672 +                value = value * 10 + (c - '0');
  30.673 +            } else {
  30.674 +                break;
  30.675 +            }
  30.676 +        }
  30.677 +        return positive ? value : -value;
  30.678 +    }
  30.679 +
  30.680 +    // The digit part of -9223372036854775808L
  30.681 +    private static final char[] LONG_MIN_REP = "9223372036854775808".toCharArray();
  30.682 +
  30.683 +    public String toString() {
  30.684 +        if (isZero()) {
  30.685 +            return "0";
  30.686 +        }
  30.687 +        StringBuffer buf = getStringBuffer();
  30.688 +        buf.append("0.");
  30.689 +        buf.append(digits, 0, count);
  30.690 +        buf.append("x10^");
  30.691 +        buf.append(decimalAt);
  30.692 +        return buf.toString();
  30.693 +    }
  30.694 +
  30.695 +    private StringBuffer tempBuffer;
  30.696 +
  30.697 +    private StringBuffer getStringBuffer() {
  30.698 +        if (tempBuffer == null) {
  30.699 +            tempBuffer = new StringBuffer(MAX_COUNT);
  30.700 +        } else {
  30.701 +            tempBuffer.setLength(0);
  30.702 +        }
  30.703 +        return tempBuffer;
  30.704 +    }
  30.705 +
  30.706 +    private void extendDigits(int len) {
  30.707 +        if (len > digits.length) {
  30.708 +            digits = new char[len];
  30.709 +        }
  30.710 +    }
  30.711 +
  30.712 +    private final char[] getDataChars(int length) {
  30.713 +        if (data == null || data.length < length) {
  30.714 +            data = new char[length];
  30.715 +        }
  30.716 +        return data;
  30.717 +    }
  30.718 +}
    31.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    31.2 +++ b/rt/emul/compact/src/main/java/java/text/DontCareFieldPosition.java	Thu Oct 03 15:40:35 2013 +0200
    31.3 @@ -0,0 +1,53 @@
    31.4 +/*
    31.5 + * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
    31.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    31.7 + *
    31.8 + * This code is free software; you can redistribute it and/or modify it
    31.9 + * under the terms of the GNU General Public License version 2 only, as
   31.10 + * published by the Free Software Foundation.  Oracle designates this
   31.11 + * particular file as subject to the "Classpath" exception as provided
   31.12 + * by Oracle in the LICENSE file that accompanied this code.
   31.13 + *
   31.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   31.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   31.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   31.17 + * version 2 for more details (a copy is included in the LICENSE file that
   31.18 + * accompanied this code).
   31.19 + *
   31.20 + * You should have received a copy of the GNU General Public License version
   31.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   31.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   31.23 + *
   31.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   31.25 + * or visit www.oracle.com if you need additional information or have any
   31.26 + * questions.
   31.27 + */
   31.28 +
   31.29 +package java.text;
   31.30 +
   31.31 +/**
   31.32 + * DontCareFieldPosition defines no-op FieldDelegate. Its
   31.33 + * singleton is used for the format methods that don't take a
   31.34 + * FieldPosition.
   31.35 + */
   31.36 +class DontCareFieldPosition extends FieldPosition {
   31.37 +    // The singleton of DontCareFieldPosition.
   31.38 +    static final FieldPosition INSTANCE = new DontCareFieldPosition();
   31.39 +
   31.40 +    private final Format.FieldDelegate noDelegate = new Format.FieldDelegate() {
   31.41 +        public void formatted(Format.Field attr, Object value, int start,
   31.42 +                              int end, StringBuffer buffer) {
   31.43 +        }
   31.44 +        public void formatted(int fieldID, Format.Field attr, Object value,
   31.45 +                              int start, int end, StringBuffer buffer) {
   31.46 +        }
   31.47 +    };
   31.48 +
   31.49 +    private DontCareFieldPosition() {
   31.50 +        super(0);
   31.51 +    }
   31.52 +
   31.53 +    Format.FieldDelegate getFieldDelegate() {
   31.54 +        return noDelegate;
   31.55 +    }
   31.56 +}
    32.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    32.2 +++ b/rt/emul/compact/src/main/java/java/text/FieldPosition.java	Thu Oct 03 15:40:35 2013 +0200
    32.3 @@ -0,0 +1,303 @@
    32.4 +/*
    32.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
    32.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    32.7 + *
    32.8 + * This code is free software; you can redistribute it and/or modify it
    32.9 + * under the terms of the GNU General Public License version 2 only, as
   32.10 + * published by the Free Software Foundation.  Oracle designates this
   32.11 + * particular file as subject to the "Classpath" exception as provided
   32.12 + * by Oracle in the LICENSE file that accompanied this code.
   32.13 + *
   32.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   32.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   32.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   32.17 + * version 2 for more details (a copy is included in the LICENSE file that
   32.18 + * accompanied this code).
   32.19 + *
   32.20 + * You should have received a copy of the GNU General Public License version
   32.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   32.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   32.23 + *
   32.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   32.25 + * or visit www.oracle.com if you need additional information or have any
   32.26 + * questions.
   32.27 + */
   32.28 +
   32.29 +/*
   32.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   32.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   32.32 + *
   32.33 + *   The original version of this source code and documentation is copyrighted
   32.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   32.35 + * materials are provided under terms of a License Agreement between Taligent
   32.36 + * and Sun. This technology is protected by multiple US and International
   32.37 + * patents. This notice and attribution to Taligent may not be removed.
   32.38 + *   Taligent is a registered trademark of Taligent, Inc.
   32.39 + *
   32.40 + */
   32.41 +
   32.42 +package java.text;
   32.43 +
   32.44 +/**
   32.45 + * <code>FieldPosition</code> is a simple class used by <code>Format</code>
   32.46 + * and its subclasses to identify fields in formatted output. Fields can
   32.47 + * be identified in two ways:
   32.48 + * <ul>
   32.49 + *  <li>By an integer constant, whose names typically end with
   32.50 + *      <code>_FIELD</code>. The constants are defined in the various
   32.51 + *      subclasses of <code>Format</code>.
   32.52 + *  <li>By a <code>Format.Field</code> constant, see <code>ERA_FIELD</code>
   32.53 + *      and its friends in <code>DateFormat</code> for an example.
   32.54 + * </ul>
   32.55 + * <p>
   32.56 + * <code>FieldPosition</code> keeps track of the position of the
   32.57 + * field within the formatted output with two indices: the index
   32.58 + * of the first character of the field and the index of the last
   32.59 + * character of the field.
   32.60 + *
   32.61 + * <p>
   32.62 + * One version of the <code>format</code> method in the various
   32.63 + * <code>Format</code> classes requires a <code>FieldPosition</code>
   32.64 + * object as an argument. You use this <code>format</code> method
   32.65 + * to perform partial formatting or to get information about the
   32.66 + * formatted output (such as the position of a field).
   32.67 + *
   32.68 + * <p>
   32.69 + * If you are interested in the positions of all attributes in the
   32.70 + * formatted string use the <code>Format</code> method
   32.71 + * <code>formatToCharacterIterator</code>.
   32.72 + *
   32.73 + * @author      Mark Davis
   32.74 + * @see         java.text.Format
   32.75 + */
   32.76 +public class FieldPosition {
   32.77 +
   32.78 +    /**
   32.79 +     * Input: Desired field to determine start and end offsets for.
   32.80 +     * The meaning depends on the subclass of Format.
   32.81 +     */
   32.82 +    int field = 0;
   32.83 +
   32.84 +    /**
   32.85 +     * Output: End offset of field in text.
   32.86 +     * If the field does not occur in the text, 0 is returned.
   32.87 +     */
   32.88 +    int endIndex = 0;
   32.89 +
   32.90 +    /**
   32.91 +     * Output: Start offset of field in text.
   32.92 +     * If the field does not occur in the text, 0 is returned.
   32.93 +     */
   32.94 +    int beginIndex = 0;
   32.95 +
   32.96 +    /**
   32.97 +     * Desired field this FieldPosition is for.
   32.98 +     */
   32.99 +    private Format.Field attribute;
  32.100 +
  32.101 +    /**
  32.102 +     * Creates a FieldPosition object for the given field.  Fields are
  32.103 +     * identified by constants, whose names typically end with _FIELD,
  32.104 +     * in the various subclasses of Format.
  32.105 +     *
  32.106 +     * @see java.text.NumberFormat#INTEGER_FIELD
  32.107 +     * @see java.text.NumberFormat#FRACTION_FIELD
  32.108 +     * @see java.text.DateFormat#YEAR_FIELD
  32.109 +     * @see java.text.DateFormat#MONTH_FIELD
  32.110 +     */
  32.111 +    public FieldPosition(int field) {
  32.112 +        this.field = field;
  32.113 +    }
  32.114 +
  32.115 +    /**
  32.116 +     * Creates a FieldPosition object for the given field constant. Fields are
  32.117 +     * identified by constants defined in the various <code>Format</code>
  32.118 +     * subclasses. This is equivalent to calling
  32.119 +     * <code>new FieldPosition(attribute, -1)</code>.
  32.120 +     *
  32.121 +     * @param attribute Format.Field constant identifying a field
  32.122 +     * @since 1.4
  32.123 +     */
  32.124 +    public FieldPosition(Format.Field attribute) {
  32.125 +        this(attribute, -1);
  32.126 +    }
  32.127 +
  32.128 +    /**
  32.129 +     * Creates a <code>FieldPosition</code> object for the given field.
  32.130 +     * The field is identified by an attribute constant from one of the
  32.131 +     * <code>Field</code> subclasses as well as an integer field ID
  32.132 +     * defined by the <code>Format</code> subclasses. <code>Format</code>
  32.133 +     * subclasses that are aware of <code>Field</code> should give precedence
  32.134 +     * to <code>attribute</code> and ignore <code>fieldID</code> if
  32.135 +     * <code>attribute</code> is not null. However, older <code>Format</code>
  32.136 +     * subclasses may not be aware of <code>Field</code> and rely on
  32.137 +     * <code>fieldID</code>. If the field has no corresponding integer
  32.138 +     * constant, <code>fieldID</code> should be -1.
  32.139 +     *
  32.140 +     * @param attribute Format.Field constant identifying a field
  32.141 +     * @param fieldID integer constantce identifying a field
  32.142 +     * @since 1.4
  32.143 +     */
  32.144 +    public FieldPosition(Format.Field attribute, int fieldID) {
  32.145 +        this.attribute = attribute;
  32.146 +        this.field = fieldID;
  32.147 +    }
  32.148 +
  32.149 +    /**
  32.150 +     * Returns the field identifier as an attribute constant
  32.151 +     * from one of the <code>Field</code> subclasses. May return null if
  32.152 +     * the field is specified only by an integer field ID.
  32.153 +     *
  32.154 +     * @return Identifier for the field
  32.155 +     * @since 1.4
  32.156 +     */
  32.157 +    public Format.Field getFieldAttribute() {
  32.158 +        return attribute;
  32.159 +    }
  32.160 +
  32.161 +    /**
  32.162 +     * Retrieves the field identifier.
  32.163 +     */
  32.164 +    public int getField() {
  32.165 +        return field;
  32.166 +    }
  32.167 +
  32.168 +    /**
  32.169 +     * Retrieves the index of the first character in the requested field.
  32.170 +     */
  32.171 +    public int getBeginIndex() {
  32.172 +        return beginIndex;
  32.173 +    }
  32.174 +
  32.175 +    /**
  32.176 +     * Retrieves the index of the character following the last character in the
  32.177 +     * requested field.
  32.178 +     */
  32.179 +    public int getEndIndex() {
  32.180 +        return endIndex;
  32.181 +    }
  32.182 +
  32.183 +    /**
  32.184 +     * Sets the begin index.  For use by subclasses of Format.
  32.185 +     * @since 1.2
  32.186 +     */
  32.187 +    public void setBeginIndex(int bi) {
  32.188 +        beginIndex = bi;
  32.189 +    }
  32.190 +
  32.191 +    /**
  32.192 +     * Sets the end index.  For use by subclasses of Format.
  32.193 +     * @since 1.2
  32.194 +     */
  32.195 +    public void setEndIndex(int ei) {
  32.196 +        endIndex = ei;
  32.197 +    }
  32.198 +
  32.199 +    /**
  32.200 +     * Returns a <code>Format.FieldDelegate</code> instance that is associated
  32.201 +     * with the FieldPosition. When the delegate is notified of the same
  32.202 +     * field the FieldPosition is associated with, the begin/end will be
  32.203 +     * adjusted.
  32.204 +     */
  32.205 +    Format.FieldDelegate getFieldDelegate() {
  32.206 +        return new Delegate();
  32.207 +    }
  32.208 +
  32.209 +    /**
  32.210 +     * Overrides equals
  32.211 +     */
  32.212 +    public boolean equals(Object obj)
  32.213 +    {
  32.214 +        if (obj == null) return false;
  32.215 +        if (!(obj instanceof FieldPosition))
  32.216 +            return false;
  32.217 +        FieldPosition other = (FieldPosition) obj;
  32.218 +        if (attribute == null) {
  32.219 +            if (other.attribute != null) {
  32.220 +                return false;
  32.221 +            }
  32.222 +        }
  32.223 +        else if (!attribute.equals(other.attribute)) {
  32.224 +            return false;
  32.225 +        }
  32.226 +        return (beginIndex == other.beginIndex
  32.227 +            && endIndex == other.endIndex
  32.228 +            && field == other.field);
  32.229 +    }
  32.230 +
  32.231 +    /**
  32.232 +     * Returns a hash code for this FieldPosition.
  32.233 +     * @return a hash code value for this object
  32.234 +     */
  32.235 +    public int hashCode() {
  32.236 +        return (field << 24) | (beginIndex << 16) | endIndex;
  32.237 +    }
  32.238 +
  32.239 +    /**
  32.240 +     * Return a string representation of this FieldPosition.
  32.241 +     * @return  a string representation of this object
  32.242 +     */
  32.243 +    public String toString() {
  32.244 +        return getClass().getName() +
  32.245 +            "[field=" + field + ",attribute=" + attribute +
  32.246 +            ",beginIndex=" + beginIndex +
  32.247 +            ",endIndex=" + endIndex + ']';
  32.248 +    }
  32.249 +
  32.250 +
  32.251 +    /**
  32.252 +     * Return true if the receiver wants a <code>Format.Field</code> value and
  32.253 +     * <code>attribute</code> is equal to it.
  32.254 +     */
  32.255 +    private boolean matchesField(Format.Field attribute) {
  32.256 +        if (this.attribute != null) {
  32.257 +            return this.attribute.equals(attribute);
  32.258 +        }
  32.259 +        return false;
  32.260 +    }
  32.261 +
  32.262 +    /**
  32.263 +     * Return true if the receiver wants a <code>Format.Field</code> value and
  32.264 +     * <code>attribute</code> is equal to it, or true if the receiver
  32.265 +     * represents an inteter constant and <code>field</code> equals it.
  32.266 +     */
  32.267 +    private boolean matchesField(Format.Field attribute, int field) {
  32.268 +        if (this.attribute != null) {
  32.269 +            return this.attribute.equals(attribute);
  32.270 +        }
  32.271 +        return (field == this.field);
  32.272 +    }
  32.273 +
  32.274 +
  32.275 +    /**
  32.276 +     * An implementation of FieldDelegate that will adjust the begin/end
  32.277 +     * of the FieldPosition if the arguments match the field of
  32.278 +     * the FieldPosition.
  32.279 +     */
  32.280 +    private class Delegate implements Format.FieldDelegate {
  32.281 +        /**
  32.282 +         * Indicates whether the field has been  encountered before. If this
  32.283 +         * is true, and <code>formatted</code> is invoked, the begin/end
  32.284 +         * are not updated.
  32.285 +         */
  32.286 +        private boolean encounteredField;
  32.287 +
  32.288 +        public void formatted(Format.Field attr, Object value, int start,
  32.289 +                              int end, StringBuffer buffer) {
  32.290 +            if (!encounteredField && matchesField(attr)) {
  32.291 +                setBeginIndex(start);
  32.292 +                setEndIndex(end);
  32.293 +                encounteredField = (start != end);
  32.294 +            }
  32.295 +        }
  32.296 +
  32.297 +        public void formatted(int fieldID, Format.Field attr, Object value,
  32.298 +                              int start, int end, StringBuffer buffer) {
  32.299 +            if (!encounteredField && matchesField(attr, fieldID)) {
  32.300 +                setBeginIndex(start);
  32.301 +                setEndIndex(end);
  32.302 +                encounteredField = (start != end);
  32.303 +            }
  32.304 +        }
  32.305 +    }
  32.306 +}
    33.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    33.2 +++ b/rt/emul/compact/src/main/java/java/text/Format.java	Thu Oct 03 15:40:35 2013 +0200
    33.3 @@ -0,0 +1,406 @@
    33.4 +/*
    33.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
    33.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    33.7 + *
    33.8 + * This code is free software; you can redistribute it and/or modify it
    33.9 + * under the terms of the GNU General Public License version 2 only, as
   33.10 + * published by the Free Software Foundation.  Oracle designates this
   33.11 + * particular file as subject to the "Classpath" exception as provided
   33.12 + * by Oracle in the LICENSE file that accompanied this code.
   33.13 + *
   33.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   33.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   33.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   33.17 + * version 2 for more details (a copy is included in the LICENSE file that
   33.18 + * accompanied this code).
   33.19 + *
   33.20 + * You should have received a copy of the GNU General Public License version
   33.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   33.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   33.23 + *
   33.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   33.25 + * or visit www.oracle.com if you need additional information or have any
   33.26 + * questions.
   33.27 + */
   33.28 +
   33.29 +/*
   33.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   33.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   33.32 + *
   33.33 + *   The original version of this source code and documentation is copyrighted
   33.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   33.35 + * materials are provided under terms of a License Agreement between Taligent
   33.36 + * and Sun. This technology is protected by multiple US and International
   33.37 + * patents. This notice and attribution to Taligent may not be removed.
   33.38 + *   Taligent is a registered trademark of Taligent, Inc.
   33.39 + *
   33.40 + */
   33.41 +
   33.42 +package java.text;
   33.43 +
   33.44 +import java.io.Serializable;
   33.45 +
   33.46 +/**
   33.47 + * <code>Format</code> is an abstract base class for formatting locale-sensitive
   33.48 + * information such as dates, messages, and numbers.
   33.49 + *
   33.50 + * <p>
   33.51 + * <code>Format</code> defines the programming interface for formatting
   33.52 + * locale-sensitive objects into <code>String</code>s (the
   33.53 + * <code>format</code> method) and for parsing <code>String</code>s back
   33.54 + * into objects (the <code>parseObject</code> method).
   33.55 + *
   33.56 + * <p>
   33.57 + * Generally, a format's <code>parseObject</code> method must be able to parse
   33.58 + * any string formatted by its <code>format</code> method. However, there may
   33.59 + * be exceptional cases where this is not possible. For example, a
   33.60 + * <code>format</code> method might create two adjacent integer numbers with
   33.61 + * no separator in between, and in this case the <code>parseObject</code> could
   33.62 + * not tell which digits belong to which number.
   33.63 + *
   33.64 + * <h4>Subclassing</h4>
   33.65 + *
   33.66 + * <p>
   33.67 + * The Java Platform provides three specialized subclasses of <code>Format</code>--
   33.68 + * <code>DateFormat</code>, <code>MessageFormat</code>, and
   33.69 + * <code>NumberFormat</code>--for formatting dates, messages, and numbers,
   33.70 + * respectively.
   33.71 + * <p>
   33.72 + * Concrete subclasses must implement three methods:
   33.73 + * <ol>
   33.74 + * <li> <code>format(Object obj, StringBuffer toAppendTo, FieldPosition pos)</code>
   33.75 + * <li> <code>formatToCharacterIterator(Object obj)</code>
   33.76 + * <li> <code>parseObject(String source, ParsePosition pos)</code>
   33.77 + * </ol>
   33.78 + * These general methods allow polymorphic parsing and formatting of objects
   33.79 + * and are used, for example, by <code>MessageFormat</code>.
   33.80 + * Subclasses often also provide additional <code>format</code> methods for
   33.81 + * specific input types as well as <code>parse</code> methods for specific
   33.82 + * result types. Any <code>parse</code> method that does not take a
   33.83 + * <code>ParsePosition</code> argument should throw <code>ParseException</code>
   33.84 + * when no text in the required format is at the beginning of the input text.
   33.85 + *
   33.86 + * <p>
   33.87 + * Most subclasses will also implement the following factory methods:
   33.88 + * <ol>
   33.89 + * <li>
   33.90 + * <code>getInstance</code> for getting a useful format object appropriate
   33.91 + * for the current locale
   33.92 + * <li>
   33.93 + * <code>getInstance(Locale)</code> for getting a useful format
   33.94 + * object appropriate for the specified locale
   33.95 + * </ol>
   33.96 + * In addition, some subclasses may also implement other
   33.97 + * <code>getXxxxInstance</code> methods for more specialized control. For
   33.98 + * example, the <code>NumberFormat</code> class provides
   33.99 + * <code>getPercentInstance</code> and <code>getCurrencyInstance</code>
  33.100 + * methods for getting specialized number formatters.
  33.101 + *
  33.102 + * <p>
  33.103 + * Subclasses of <code>Format</code> that allow programmers to create objects
  33.104 + * for locales (with <code>getInstance(Locale)</code> for example)
  33.105 + * must also implement the following class method:
  33.106 + * <blockquote>
  33.107 + * <pre>
  33.108 + * public static Locale[] getAvailableLocales()
  33.109 + * </pre>
  33.110 + * </blockquote>
  33.111 + *
  33.112 + * <p>
  33.113 + * And finally subclasses may define a set of constants to identify the various
  33.114 + * fields in the formatted output. These constants are used to create a FieldPosition
  33.115 + * object which identifies what information is contained in the field and its
  33.116 + * position in the formatted result. These constants should be named
  33.117 + * <code><em>item</em>_FIELD</code> where <code><em>item</em></code> identifies
  33.118 + * the field. For examples of these constants, see <code>ERA_FIELD</code> and its
  33.119 + * friends in {@link DateFormat}.
  33.120 + *
  33.121 + * <h4><a name="synchronization">Synchronization</a></h4>
  33.122 + *
  33.123 + * <p>
  33.124 + * Formats are generally not synchronized.
  33.125 + * It is recommended to create separate format instances for each thread.
  33.126 + * If multiple threads access a format concurrently, it must be synchronized
  33.127 + * externally.
  33.128 + *
  33.129 + * @see          java.text.ParsePosition
  33.130 + * @see          java.text.FieldPosition
  33.131 + * @see          java.text.NumberFormat
  33.132 + * @see          java.text.DateFormat
  33.133 + * @see          java.text.MessageFormat
  33.134 + * @author       Mark Davis
  33.135 + */
  33.136 +public abstract class Format implements Serializable, Cloneable {
  33.137 +
  33.138 +    private static final long serialVersionUID = -299282585814624189L;
  33.139 +
  33.140 +    /**
  33.141 +     * Sole constructor.  (For invocation by subclass constructors, typically
  33.142 +     * implicit.)
  33.143 +     */
  33.144 +    protected Format() {
  33.145 +    }
  33.146 +
  33.147 +    /**
  33.148 +     * Formats an object to produce a string. This is equivalent to
  33.149 +     * <blockquote>
  33.150 +     * {@link #format(Object, StringBuffer, FieldPosition) format}<code>(obj,
  33.151 +     *         new StringBuffer(), new FieldPosition(0)).toString();</code>
  33.152 +     * </blockquote>
  33.153 +     *
  33.154 +     * @param obj    The object to format
  33.155 +     * @return       Formatted string.
  33.156 +     * @exception IllegalArgumentException if the Format cannot format the given
  33.157 +     *            object
  33.158 +     */
  33.159 +    public final String format (Object obj) {
  33.160 +        return format(obj, new StringBuffer(), new FieldPosition(0)).toString();
  33.161 +    }
  33.162 +
  33.163 +    /**
  33.164 +     * Formats an object and appends the resulting text to a given string
  33.165 +     * buffer.
  33.166 +     * If the <code>pos</code> argument identifies a field used by the format,
  33.167 +     * then its indices are set to the beginning and end of the first such
  33.168 +     * field encountered.
  33.169 +     *
  33.170 +     * @param obj    The object to format
  33.171 +     * @param toAppendTo    where the text is to be appended
  33.172 +     * @param pos    A <code>FieldPosition</code> identifying a field
  33.173 +     *               in the formatted text
  33.174 +     * @return       the string buffer passed in as <code>toAppendTo</code>,
  33.175 +     *               with formatted text appended
  33.176 +     * @exception NullPointerException if <code>toAppendTo</code> or
  33.177 +     *            <code>pos</code> is null
  33.178 +     * @exception IllegalArgumentException if the Format cannot format the given
  33.179 +     *            object
  33.180 +     */
  33.181 +    public abstract StringBuffer format(Object obj,
  33.182 +                    StringBuffer toAppendTo,
  33.183 +                    FieldPosition pos);
  33.184 +
  33.185 +    /**
  33.186 +     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
  33.187 +     * You can use the returned <code>AttributedCharacterIterator</code>
  33.188 +     * to build the resulting String, as well as to determine information
  33.189 +     * about the resulting String.
  33.190 +     * <p>
  33.191 +     * Each attribute key of the AttributedCharacterIterator will be of type
  33.192 +     * <code>Field</code>. It is up to each <code>Format</code> implementation
  33.193 +     * to define what the legal values are for each attribute in the
  33.194 +     * <code>AttributedCharacterIterator</code>, but typically the attribute
  33.195 +     * key is also used as the attribute value.
  33.196 +     * <p>The default implementation creates an
  33.197 +     * <code>AttributedCharacterIterator</code> with no attributes. Subclasses
  33.198 +     * that support fields should override this and create an
  33.199 +     * <code>AttributedCharacterIterator</code> with meaningful attributes.
  33.200 +     *
  33.201 +     * @exception NullPointerException if obj is null.
  33.202 +     * @exception IllegalArgumentException when the Format cannot format the
  33.203 +     *            given object.
  33.204 +     * @param obj The object to format
  33.205 +     * @return AttributedCharacterIterator describing the formatted value.
  33.206 +     * @since 1.4
  33.207 +     */
  33.208 +    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
  33.209 +        return createAttributedCharacterIterator(format(obj));
  33.210 +    }
  33.211 +
  33.212 +    /**
  33.213 +     * Parses text from a string to produce an object.
  33.214 +     * <p>
  33.215 +     * The method attempts to parse text starting at the index given by
  33.216 +     * <code>pos</code>.
  33.217 +     * If parsing succeeds, then the index of <code>pos</code> is updated
  33.218 +     * to the index after the last character used (parsing does not necessarily
  33.219 +     * use all characters up to the end of the string), and the parsed
  33.220 +     * object is returned. The updated <code>pos</code> can be used to
  33.221 +     * indicate the starting point for the next call to this method.
  33.222 +     * If an error occurs, then the index of <code>pos</code> is not
  33.223 +     * changed, the error index of <code>pos</code> is set to the index of
  33.224 +     * the character where the error occurred, and null is returned.
  33.225 +     *
  33.226 +     * @param source A <code>String</code>, part of which should be parsed.
  33.227 +     * @param pos A <code>ParsePosition</code> object with index and error
  33.228 +     *            index information as described above.
  33.229 +     * @return An <code>Object</code> parsed from the string. In case of
  33.230 +     *         error, returns null.
  33.231 +     * @exception NullPointerException if <code>pos</code> is null.
  33.232 +     */
  33.233 +    public abstract Object parseObject (String source, ParsePosition pos);
  33.234 +
  33.235 +    /**
  33.236 +     * Parses text from the beginning of the given string to produce an object.
  33.237 +     * The method may not use the entire text of the given string.
  33.238 +     *
  33.239 +     * @param source A <code>String</code> whose beginning should be parsed.
  33.240 +     * @return An <code>Object</code> parsed from the string.
  33.241 +     * @exception ParseException if the beginning of the specified string
  33.242 +     *            cannot be parsed.
  33.243 +     */
  33.244 +    public Object parseObject(String source) throws ParseException {
  33.245 +        ParsePosition pos = new ParsePosition(0);
  33.246 +        Object result = parseObject(source, pos);
  33.247 +        if (pos.index == 0) {
  33.248 +            throw new ParseException("Format.parseObject(String) failed",
  33.249 +                pos.errorIndex);
  33.250 +        }
  33.251 +        return result;
  33.252 +    }
  33.253 +
  33.254 +    /**
  33.255 +     * Creates and returns a copy of this object.
  33.256 +     *
  33.257 +     * @return a clone of this instance.
  33.258 +     */
  33.259 +    public Object clone() {
  33.260 +        try {
  33.261 +            return super.clone();
  33.262 +        } catch (CloneNotSupportedException e) {
  33.263 +            // will never happen
  33.264 +            return null;
  33.265 +        }
  33.266 +    }
  33.267 +
  33.268 +    //
  33.269 +    // Convenience methods for creating AttributedCharacterIterators from
  33.270 +    // different parameters.
  33.271 +    //
  33.272 +
  33.273 +    /**
  33.274 +     * Creates an <code>AttributedCharacterIterator</code> for the String
  33.275 +     * <code>s</code>.
  33.276 +     *
  33.277 +     * @param s String to create AttributedCharacterIterator from
  33.278 +     * @return AttributedCharacterIterator wrapping s
  33.279 +     */
  33.280 +    AttributedCharacterIterator createAttributedCharacterIterator(String s) {
  33.281 +        AttributedString as = new AttributedString(s);
  33.282 +
  33.283 +        return as.getIterator();
  33.284 +    }
  33.285 +
  33.286 +    /**
  33.287 +     * Creates an <code>AttributedCharacterIterator</code> containg the
  33.288 +     * concatenated contents of the passed in
  33.289 +     * <code>AttributedCharacterIterator</code>s.
  33.290 +     *
  33.291 +     * @param iterators AttributedCharacterIterators used to create resulting
  33.292 +     *                  AttributedCharacterIterators
  33.293 +     * @return AttributedCharacterIterator wrapping passed in
  33.294 +     *         AttributedCharacterIterators
  33.295 +     */
  33.296 +    AttributedCharacterIterator createAttributedCharacterIterator(
  33.297 +                       AttributedCharacterIterator[] iterators) {
  33.298 +        AttributedString as = new AttributedString(iterators);
  33.299 +
  33.300 +        return as.getIterator();
  33.301 +    }
  33.302 +
  33.303 +    /**
  33.304 +     * Returns an AttributedCharacterIterator with the String
  33.305 +     * <code>string</code> and additional key/value pair <code>key</code>,
  33.306 +     * <code>value</code>.
  33.307 +     *
  33.308 +     * @param string String to create AttributedCharacterIterator from
  33.309 +     * @param key Key for AttributedCharacterIterator
  33.310 +     * @param value Value associated with key in AttributedCharacterIterator
  33.311 +     * @return AttributedCharacterIterator wrapping args
  33.312 +     */
  33.313 +    AttributedCharacterIterator createAttributedCharacterIterator(
  33.314 +                      String string, AttributedCharacterIterator.Attribute key,
  33.315 +                      Object value) {
  33.316 +        AttributedString as = new AttributedString(string);
  33.317 +
  33.318 +        as.addAttribute(key, value);
  33.319 +        return as.getIterator();
  33.320 +    }
  33.321 +
  33.322 +    /**
  33.323 +     * Creates an AttributedCharacterIterator with the contents of
  33.324 +     * <code>iterator</code> and the additional attribute <code>key</code>
  33.325 +     * <code>value</code>.
  33.326 +     *
  33.327 +     * @param iterator Initial AttributedCharacterIterator to add arg to
  33.328 +     * @param key Key for AttributedCharacterIterator
  33.329 +     * @param value Value associated with key in AttributedCharacterIterator
  33.330 +     * @return AttributedCharacterIterator wrapping args
  33.331 +     */
  33.332 +    AttributedCharacterIterator createAttributedCharacterIterator(
  33.333 +              AttributedCharacterIterator iterator,
  33.334 +              AttributedCharacterIterator.Attribute key, Object value) {
  33.335 +        AttributedString as = new AttributedString(iterator);
  33.336 +
  33.337 +        as.addAttribute(key, value);
  33.338 +        return as.getIterator();
  33.339 +    }
  33.340 +
  33.341 +
  33.342 +    /**
  33.343 +     * Defines constants that are used as attribute keys in the
  33.344 +     * <code>AttributedCharacterIterator</code> returned
  33.345 +     * from <code>Format.formatToCharacterIterator</code> and as
  33.346 +     * field identifiers in <code>FieldPosition</code>.
  33.347 +     *
  33.348 +     * @since 1.4
  33.349 +     */
  33.350 +    public static class Field extends AttributedCharacterIterator.Attribute {
  33.351 +
  33.352 +        // Proclaim serial compatibility with 1.4 FCS
  33.353 +        private static final long serialVersionUID = 276966692217360283L;
  33.354 +
  33.355 +        /**
  33.356 +         * Creates a Field with the specified name.
  33.357 +         *
  33.358 +         * @param name Name of the attribute
  33.359 +         */
  33.360 +        protected Field(String name) {
  33.361 +            super(name);
  33.362 +        }
  33.363 +    }
  33.364 +
  33.365 +
  33.366 +    /**
  33.367 +     * FieldDelegate is notified by the various <code>Format</code>
  33.368 +     * implementations as they are formatting the Objects. This allows for
  33.369 +     * storage of the individual sections of the formatted String for
  33.370 +     * later use, such as in a <code>FieldPosition</code> or for an
  33.371 +     * <code>AttributedCharacterIterator</code>.
  33.372 +     * <p>
  33.373 +     * Delegates should NOT assume that the <code>Format</code> will notify
  33.374 +     * the delegate of fields in any particular order.
  33.375 +     *
  33.376 +     * @see FieldPosition.Delegate
  33.377 +     * @see CharacterIteratorFieldDelegate
  33.378 +     */
  33.379 +    interface FieldDelegate {
  33.380 +        /**
  33.381 +         * Notified when a particular region of the String is formatted. This
  33.382 +         * method will be invoked if there is no corresponding integer field id
  33.383 +         * matching <code>attr</code>.
  33.384 +         *
  33.385 +         * @param attr Identifies the field matched
  33.386 +         * @param value Value associated with the field
  33.387 +         * @param start Beginning location of the field, will be >= 0
  33.388 +         * @param end End of the field, will be >= start and <= buffer.length()
  33.389 +         * @param buffer Contains current formatted value, receiver should
  33.390 +         *        NOT modify it.
  33.391 +         */
  33.392 +        public void formatted(Format.Field attr, Object value, int start,
  33.393 +                              int end, StringBuffer buffer);
  33.394 +
  33.395 +        /**
  33.396 +         * Notified when a particular region of the String is formatted.
  33.397 +         *
  33.398 +         * @param fieldID Identifies the field by integer
  33.399 +         * @param attr Identifies the field matched
  33.400 +         * @param value Value associated with the field
  33.401 +         * @param start Beginning location of the field, will be >= 0
  33.402 +         * @param end End of the field, will be >= start and <= buffer.length()
  33.403 +         * @param buffer Contains current formatted value, receiver should
  33.404 +         *        NOT modify it.
  33.405 +         */
  33.406 +        public void formatted(int fieldID, Format.Field attr, Object value,
  33.407 +                              int start, int end, StringBuffer buffer);
  33.408 +    }
  33.409 +}
    34.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    34.2 +++ b/rt/emul/compact/src/main/java/java/text/MessageFormat.java	Thu Oct 03 15:40:35 2013 +0200
    34.3 @@ -0,0 +1,1594 @@
    34.4 +/*
    34.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
    34.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    34.7 + *
    34.8 + * This code is free software; you can redistribute it and/or modify it
    34.9 + * under the terms of the GNU General Public License version 2 only, as
   34.10 + * published by the Free Software Foundation.  Oracle designates this
   34.11 + * particular file as subject to the "Classpath" exception as provided
   34.12 + * by Oracle in the LICENSE file that accompanied this code.
   34.13 + *
   34.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   34.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   34.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   34.17 + * version 2 for more details (a copy is included in the LICENSE file that
   34.18 + * accompanied this code).
   34.19 + *
   34.20 + * You should have received a copy of the GNU General Public License version
   34.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   34.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   34.23 + *
   34.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   34.25 + * or visit www.oracle.com if you need additional information or have any
   34.26 + * questions.
   34.27 + */
   34.28 +
   34.29 +/*
   34.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   34.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   34.32 + *
   34.33 + *   The original version of this source code and documentation is copyrighted
   34.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   34.35 + * materials are provided under terms of a License Agreement between Taligent
   34.36 + * and Sun. This technology is protected by multiple US and International
   34.37 + * patents. This notice and attribution to Taligent may not be removed.
   34.38 + *   Taligent is a registered trademark of Taligent, Inc.
   34.39 + *
   34.40 + */
   34.41 +
   34.42 +package java.text;
   34.43 +
   34.44 +import java.io.InvalidObjectException;
   34.45 +import java.io.IOException;
   34.46 +import java.io.ObjectInputStream;
   34.47 +import java.text.DecimalFormat;
   34.48 +import java.util.ArrayList;
   34.49 +import java.util.Arrays;
   34.50 +import java.util.Date;
   34.51 +import java.util.List;
   34.52 +import java.util.Locale;
   34.53 +
   34.54 +
   34.55 +/**
   34.56 + * <code>MessageFormat</code> provides a means to produce concatenated
   34.57 + * messages in a language-neutral way. Use this to construct messages
   34.58 + * displayed for end users.
   34.59 + *
   34.60 + * <p>
   34.61 + * <code>MessageFormat</code> takes a set of objects, formats them, then
   34.62 + * inserts the formatted strings into the pattern at the appropriate places.
   34.63 + *
   34.64 + * <p>
   34.65 + * <strong>Note:</strong>
   34.66 + * <code>MessageFormat</code> differs from the other <code>Format</code>
   34.67 + * classes in that you create a <code>MessageFormat</code> object with one
   34.68 + * of its constructors (not with a <code>getInstance</code> style factory
   34.69 + * method). The factory methods aren't necessary because <code>MessageFormat</code>
   34.70 + * itself doesn't implement locale specific behavior. Any locale specific
   34.71 + * behavior is defined by the pattern that you provide as well as the
   34.72 + * subformats used for inserted arguments.
   34.73 + *
   34.74 + * <h4><a name="patterns">Patterns and Their Interpretation</a></h4>
   34.75 + *
   34.76 + * <code>MessageFormat</code> uses patterns of the following form:
   34.77 + * <blockquote><pre>
   34.78 + * <i>MessageFormatPattern:</i>
   34.79 + *         <i>String</i>
   34.80 + *         <i>MessageFormatPattern</i> <i>FormatElement</i> <i>String</i>
   34.81 + *
   34.82 + * <i>FormatElement:</i>
   34.83 + *         { <i>ArgumentIndex</i> }
   34.84 + *         { <i>ArgumentIndex</i> , <i>FormatType</i> }
   34.85 + *         { <i>ArgumentIndex</i> , <i>FormatType</i> , <i>FormatStyle</i> }
   34.86 + *
   34.87 + * <i>FormatType: one of </i>
   34.88 + *         number date time choice
   34.89 + *
   34.90 + * <i>FormatStyle:</i>
   34.91 + *         short
   34.92 + *         medium
   34.93 + *         long
   34.94 + *         full
   34.95 + *         integer
   34.96 + *         currency
   34.97 + *         percent
   34.98 + *         <i>SubformatPattern</i>
   34.99 + * </pre></blockquote>
  34.100 + *
  34.101 + * <p>Within a <i>String</i>, a pair of single quotes can be used to
  34.102 + * quote any arbitrary characters except single quotes. For example,
  34.103 + * pattern string <code>"'{0}'"</code> represents string
  34.104 + * <code>"{0}"</code>, not a <i>FormatElement</i>. A single quote itself
  34.105 + * must be represented by doubled single quotes {@code ''} throughout a
  34.106 + * <i>String</i>.  For example, pattern string <code>"'{''}'"</code> is
  34.107 + * interpreted as a sequence of <code>'{</code> (start of quoting and a
  34.108 + * left curly brace), <code>''</code> (a single quote), and
  34.109 + * <code>}'</code> (a right curly brace and end of quoting),
  34.110 + * <em>not</em> <code>'{'</code> and <code>'}'</code> (quoted left and
  34.111 + * right curly braces): representing string <code>"{'}"</code>,
  34.112 + * <em>not</em> <code>"{}"</code>.
  34.113 + *
  34.114 + * <p>A <i>SubformatPattern</i> is interpreted by its corresponding
  34.115 + * subformat, and subformat-dependent pattern rules apply. For example,
  34.116 + * pattern string <code>"{1,number,<u>$'#',##</u>}"</code>
  34.117 + * (<i>SubformatPattern</i> with underline) will produce a number format
  34.118 + * with the pound-sign quoted, with a result such as: {@code
  34.119 + * "$#31,45"}. Refer to each {@code Format} subclass documentation for
  34.120 + * details.
  34.121 + *
  34.122 + * <p>Any unmatched quote is treated as closed at the end of the given
  34.123 + * pattern. For example, pattern string {@code "'{0}"} is treated as
  34.124 + * pattern {@code "'{0}'"}.
  34.125 + *
  34.126 + * <p>Any curly braces within an unquoted pattern must be balanced. For
  34.127 + * example, <code>"ab {0} de"</code> and <code>"ab '}' de"</code> are
  34.128 + * valid patterns, but <code>"ab {0'}' de"</code>, <code>"ab } de"</code>
  34.129 + * and <code>"''{''"</code> are not.
  34.130 + *
  34.131 + * <p>
  34.132 + * <dl><dt><b>Warning:</b><dd>The rules for using quotes within message
  34.133 + * format patterns unfortunately have shown to be somewhat confusing.
  34.134 + * In particular, it isn't always obvious to localizers whether single
  34.135 + * quotes need to be doubled or not. Make sure to inform localizers about
  34.136 + * the rules, and tell them (for example, by using comments in resource
  34.137 + * bundle source files) which strings will be processed by {@code MessageFormat}.
  34.138 + * Note that localizers may need to use single quotes in translated
  34.139 + * strings where the original version doesn't have them.
  34.140 + * </dl>
  34.141 + * <p>
  34.142 + * The <i>ArgumentIndex</i> value is a non-negative integer written
  34.143 + * using the digits {@code '0'} through {@code '9'}, and represents an index into the
  34.144 + * {@code arguments} array passed to the {@code format} methods
  34.145 + * or the result array returned by the {@code parse} methods.
  34.146 + * <p>
  34.147 + * The <i>FormatType</i> and <i>FormatStyle</i> values are used to create
  34.148 + * a {@code Format} instance for the format element. The following
  34.149 + * table shows how the values map to {@code Format} instances. Combinations not
  34.150 + * shown in the table are illegal. A <i>SubformatPattern</i> must
  34.151 + * be a valid pattern string for the {@code Format} subclass used.
  34.152 + * <p>
  34.153 + * <table border=1 summary="Shows how FormatType and FormatStyle values map to Format instances">
  34.154 + *    <tr>
  34.155 + *       <th id="ft" class="TableHeadingColor">FormatType
  34.156 + *       <th id="fs" class="TableHeadingColor">FormatStyle
  34.157 + *       <th id="sc" class="TableHeadingColor">Subformat Created
  34.158 + *    <tr>
  34.159 + *       <td headers="ft"><i>(none)</i>
  34.160 + *       <td headers="fs"><i>(none)</i>
  34.161 + *       <td headers="sc"><code>null</code>
  34.162 + *    <tr>
  34.163 + *       <td headers="ft" rowspan=5><code>number</code>
  34.164 + *       <td headers="fs"><i>(none)</i>
  34.165 + *       <td headers="sc">{@link NumberFormat#getInstance(Locale) NumberFormat.getInstance}{@code (getLocale())}
  34.166 + *    <tr>
  34.167 + *       <td headers="fs"><code>integer</code>
  34.168 + *       <td headers="sc">{@link NumberFormat#getIntegerInstance(Locale) NumberFormat.getIntegerInstance}{@code (getLocale())}
  34.169 + *    <tr>
  34.170 + *       <td headers="fs"><code>currency</code>
  34.171 + *       <td headers="sc">{@link NumberFormat#getCurrencyInstance(Locale) NumberFormat.getCurrencyInstance}{@code (getLocale())}
  34.172 + *    <tr>
  34.173 + *       <td headers="fs"><code>percent</code>
  34.174 + *       <td headers="sc">{@link NumberFormat#getPercentInstance(Locale) NumberFormat.getPercentInstance}{@code (getLocale())}
  34.175 + *    <tr>
  34.176 + *       <td headers="fs"><i>SubformatPattern</i>
  34.177 + *       <td headers="sc">{@code new} {@link DecimalFormat#DecimalFormat(String,DecimalFormatSymbols) DecimalFormat}{@code (subformatPattern,} {@link DecimalFormatSymbols#getInstance(Locale) DecimalFormatSymbols.getInstance}{@code (getLocale()))}
  34.178 + *    <tr>
  34.179 + *       <td headers="ft" rowspan=6><code>date</code>
  34.180 + *       <td headers="fs"><i>(none)</i>
  34.181 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
  34.182 + *    <tr>
  34.183 + *       <td headers="fs"><code>short</code>
  34.184 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
  34.185 + *    <tr>
  34.186 + *       <td headers="fs"><code>medium</code>
  34.187 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
  34.188 + *    <tr>
  34.189 + *       <td headers="fs"><code>long</code>
  34.190 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
  34.191 + *    <tr>
  34.192 + *       <td headers="fs"><code>full</code>
  34.193 + *       <td headers="sc">{@link DateFormat#getDateInstance(int,Locale) DateFormat.getDateInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
  34.194 + *    <tr>
  34.195 + *       <td headers="fs"><i>SubformatPattern</i>
  34.196 + *       <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
  34.197 + *    <tr>
  34.198 + *       <td headers="ft" rowspan=6><code>time</code>
  34.199 + *       <td headers="fs"><i>(none)</i>
  34.200 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
  34.201 + *    <tr>
  34.202 + *       <td headers="fs"><code>short</code>
  34.203 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#SHORT}{@code , getLocale())}
  34.204 + *    <tr>
  34.205 + *       <td headers="fs"><code>medium</code>
  34.206 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#DEFAULT}{@code , getLocale())}
  34.207 + *    <tr>
  34.208 + *       <td headers="fs"><code>long</code>
  34.209 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#LONG}{@code , getLocale())}
  34.210 + *    <tr>
  34.211 + *       <td headers="fs"><code>full</code>
  34.212 + *       <td headers="sc">{@link DateFormat#getTimeInstance(int,Locale) DateFormat.getTimeInstance}{@code (}{@link DateFormat#FULL}{@code , getLocale())}
  34.213 + *    <tr>
  34.214 + *       <td headers="fs"><i>SubformatPattern</i>
  34.215 + *       <td headers="sc">{@code new} {@link SimpleDateFormat#SimpleDateFormat(String,Locale) SimpleDateFormat}{@code (subformatPattern, getLocale())}
  34.216 + *    <tr>
  34.217 + *       <td headers="ft"><code>choice</code>
  34.218 + *       <td headers="fs"><i>SubformatPattern</i>
  34.219 + *       <td headers="sc">{@code new} {@link ChoiceFormat#ChoiceFormat(String) ChoiceFormat}{@code (subformatPattern)}
  34.220 + * </table>
  34.221 + * <p>
  34.222 + *
  34.223 + * <h4>Usage Information</h4>
  34.224 + *
  34.225 + * <p>
  34.226 + * Here are some examples of usage.
  34.227 + * In real internationalized programs, the message format pattern and other
  34.228 + * static strings will, of course, be obtained from resource bundles.
  34.229 + * Other parameters will be dynamically determined at runtime.
  34.230 + * <p>
  34.231 + * The first example uses the static method <code>MessageFormat.format</code>,
  34.232 + * which internally creates a <code>MessageFormat</code> for one-time use:
  34.233 + * <blockquote><pre>
  34.234 + * int planet = 7;
  34.235 + * String event = "a disturbance in the Force";
  34.236 + *
  34.237 + * String result = MessageFormat.format(
  34.238 + *     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
  34.239 + *     planet, new Date(), event);
  34.240 + * </pre></blockquote>
  34.241 + * The output is:
  34.242 + * <blockquote><pre>
  34.243 + * At 12:30 PM on Jul 3, 2053, there was a disturbance in the Force on planet 7.
  34.244 + * </pre></blockquote>
  34.245 + *
  34.246 + * <p>
  34.247 + * The following example creates a <code>MessageFormat</code> instance that
  34.248 + * can be used repeatedly:
  34.249 + * <blockquote><pre>
  34.250 + * int fileCount = 1273;
  34.251 + * String diskName = "MyDisk";
  34.252 + * Object[] testArgs = {new Long(fileCount), diskName};
  34.253 + *
  34.254 + * MessageFormat form = new MessageFormat(
  34.255 + *     "The disk \"{1}\" contains {0} file(s).");
  34.256 + *
  34.257 + * System.out.println(form.format(testArgs));
  34.258 + * </pre></blockquote>
  34.259 + * The output with different values for <code>fileCount</code>:
  34.260 + * <blockquote><pre>
  34.261 + * The disk "MyDisk" contains 0 file(s).
  34.262 + * The disk "MyDisk" contains 1 file(s).
  34.263 + * The disk "MyDisk" contains 1,273 file(s).
  34.264 + * </pre></blockquote>
  34.265 + *
  34.266 + * <p>
  34.267 + * For more sophisticated patterns, you can use a <code>ChoiceFormat</code>
  34.268 + * to produce correct forms for singular and plural:
  34.269 + * <blockquote><pre>
  34.270 + * MessageFormat form = new MessageFormat("The disk \"{1}\" contains {0}.");
  34.271 + * double[] filelimits = {0,1,2};
  34.272 + * String[] filepart = {"no files","one file","{0,number} files"};
  34.273 + * ChoiceFormat fileform = new ChoiceFormat(filelimits, filepart);
  34.274 + * form.setFormatByArgumentIndex(0, fileform);
  34.275 + *
  34.276 + * int fileCount = 1273;
  34.277 + * String diskName = "MyDisk";
  34.278 + * Object[] testArgs = {new Long(fileCount), diskName};
  34.279 + *
  34.280 + * System.out.println(form.format(testArgs));
  34.281 + * </pre></blockquote>
  34.282 + * The output with different values for <code>fileCount</code>:
  34.283 + * <blockquote><pre>
  34.284 + * The disk "MyDisk" contains no files.
  34.285 + * The disk "MyDisk" contains one file.
  34.286 + * The disk "MyDisk" contains 1,273 files.
  34.287 + * </pre></blockquote>
  34.288 + *
  34.289 + * <p>
  34.290 + * You can create the <code>ChoiceFormat</code> programmatically, as in the
  34.291 + * above example, or by using a pattern. See {@link ChoiceFormat}
  34.292 + * for more information.
  34.293 + * <blockquote><pre>
  34.294 + * form.applyPattern(
  34.295 + *    "There {0,choice,0#are no files|1#is one file|1&lt;are {0,number,integer} files}.");
  34.296 + * </pre></blockquote>
  34.297 + *
  34.298 + * <p>
  34.299 + * <strong>Note:</strong> As we see above, the string produced
  34.300 + * by a <code>ChoiceFormat</code> in <code>MessageFormat</code> is treated as special;
  34.301 + * occurrences of '{' are used to indicate subformats, and cause recursion.
  34.302 + * If you create both a <code>MessageFormat</code> and <code>ChoiceFormat</code>
  34.303 + * programmatically (instead of using the string patterns), then be careful not to
  34.304 + * produce a format that recurses on itself, which will cause an infinite loop.
  34.305 + * <p>
  34.306 + * When a single argument is parsed more than once in the string, the last match
  34.307 + * will be the final result of the parsing.  For example,
  34.308 + * <blockquote><pre>
  34.309 + * MessageFormat mf = new MessageFormat("{0,number,#.##}, {0,number,#.#}");
  34.310 + * Object[] objs = {new Double(3.1415)};
  34.311 + * String result = mf.format( objs );
  34.312 + * // result now equals "3.14, 3.1"
  34.313 + * objs = null;
  34.314 + * objs = mf.parse(result, new ParsePosition(0));
  34.315 + * // objs now equals {new Double(3.1)}
  34.316 + * </pre></blockquote>
  34.317 + *
  34.318 + * <p>
  34.319 + * Likewise, parsing with a {@code MessageFormat} object using patterns containing
  34.320 + * multiple occurrences of the same argument would return the last match.  For
  34.321 + * example,
  34.322 + * <blockquote><pre>
  34.323 + * MessageFormat mf = new MessageFormat("{0}, {0}, {0}");
  34.324 + * String forParsing = "x, y, z";
  34.325 + * Object[] objs = mf.parse(forParsing, new ParsePosition(0));
  34.326 + * // result now equals {new String("z")}
  34.327 + * </pre></blockquote>
  34.328 + *
  34.329 + * <h4><a name="synchronization">Synchronization</a></h4>
  34.330 + *
  34.331 + * <p>
  34.332 + * Message formats are not synchronized.
  34.333 + * It is recommended to create separate format instances for each thread.
  34.334 + * If multiple threads access a format concurrently, it must be synchronized
  34.335 + * externally.
  34.336 + *
  34.337 + * @see          java.util.Locale
  34.338 + * @see          Format
  34.339 + * @see          NumberFormat
  34.340 + * @see          DecimalFormat
  34.341 + * @see          DecimalFormatSymbols
  34.342 + * @see          ChoiceFormat
  34.343 + * @see          DateFormat
  34.344 + * @see          SimpleDateFormat
  34.345 + *
  34.346 + * @author       Mark Davis
  34.347 + */
  34.348 +
  34.349 +public class MessageFormat extends Format {
  34.350 +
  34.351 +    private static final long serialVersionUID = 6479157306784022952L;
  34.352 +
  34.353 +    /**
  34.354 +     * Constructs a MessageFormat for the default locale and the
  34.355 +     * specified pattern.
  34.356 +     * The constructor first sets the locale, then parses the pattern and
  34.357 +     * creates a list of subformats for the format elements contained in it.
  34.358 +     * Patterns and their interpretation are specified in the
  34.359 +     * <a href="#patterns">class description</a>.
  34.360 +     *
  34.361 +     * @param pattern the pattern for this message format
  34.362 +     * @exception IllegalArgumentException if the pattern is invalid
  34.363 +     */
  34.364 +    public MessageFormat(String pattern) {
  34.365 +        this.locale = Locale.getDefault(Locale.Category.FORMAT);
  34.366 +        applyPattern(pattern);
  34.367 +    }
  34.368 +
  34.369 +    /**
  34.370 +     * Constructs a MessageFormat for the specified locale and
  34.371 +     * pattern.
  34.372 +     * The constructor first sets the locale, then parses the pattern and
  34.373 +     * creates a list of subformats for the format elements contained in it.
  34.374 +     * Patterns and their interpretation are specified in the
  34.375 +     * <a href="#patterns">class description</a>.
  34.376 +     *
  34.377 +     * @param pattern the pattern for this message format
  34.378 +     * @param locale the locale for this message format
  34.379 +     * @exception IllegalArgumentException if the pattern is invalid
  34.380 +     * @since 1.4
  34.381 +     */
  34.382 +    public MessageFormat(String pattern, Locale locale) {
  34.383 +        this.locale = locale;
  34.384 +        applyPattern(pattern);
  34.385 +    }
  34.386 +
  34.387 +    /**
  34.388 +     * Sets the locale to be used when creating or comparing subformats.
  34.389 +     * This affects subsequent calls
  34.390 +     * <ul>
  34.391 +     * <li>to the {@link #applyPattern applyPattern}
  34.392 +     *     and {@link #toPattern toPattern} methods if format elements specify
  34.393 +     *     a format type and therefore have the subformats created in the
  34.394 +     *     <code>applyPattern</code> method, as well as
  34.395 +     * <li>to the <code>format</code> and
  34.396 +     *     {@link #formatToCharacterIterator formatToCharacterIterator} methods
  34.397 +     *     if format elements do not specify a format type and therefore have
  34.398 +     *     the subformats created in the formatting methods.
  34.399 +     * </ul>
  34.400 +     * Subformats that have already been created are not affected.
  34.401 +     *
  34.402 +     * @param locale the locale to be used when creating or comparing subformats
  34.403 +     */
  34.404 +    public void setLocale(Locale locale) {
  34.405 +        this.locale = locale;
  34.406 +    }
  34.407 +
  34.408 +    /**
  34.409 +     * Gets the locale that's used when creating or comparing subformats.
  34.410 +     *
  34.411 +     * @return the locale used when creating or comparing subformats
  34.412 +     */
  34.413 +    public Locale getLocale() {
  34.414 +        return locale;
  34.415 +    }
  34.416 +
  34.417 +
  34.418 +    /**
  34.419 +     * Sets the pattern used by this message format.
  34.420 +     * The method parses the pattern and creates a list of subformats
  34.421 +     * for the format elements contained in it.
  34.422 +     * Patterns and their interpretation are specified in the
  34.423 +     * <a href="#patterns">class description</a>.
  34.424 +     *
  34.425 +     * @param pattern the pattern for this message format
  34.426 +     * @exception IllegalArgumentException if the pattern is invalid
  34.427 +     */
  34.428 +    public void applyPattern(String pattern) {
  34.429 +            StringBuilder[] segments = new StringBuilder[4];
  34.430 +            // Allocate only segments[SEG_RAW] here. The rest are
  34.431 +            // allocated on demand.
  34.432 +            segments[SEG_RAW] = new StringBuilder();
  34.433 +
  34.434 +            int part = SEG_RAW;
  34.435 +            int formatNumber = 0;
  34.436 +            boolean inQuote = false;
  34.437 +            int braceStack = 0;
  34.438 +            maxOffset = -1;
  34.439 +            for (int i = 0; i < pattern.length(); ++i) {
  34.440 +                char ch = pattern.charAt(i);
  34.441 +                if (part == SEG_RAW) {
  34.442 +                    if (ch == '\'') {
  34.443 +                        if (i + 1 < pattern.length()
  34.444 +                            && pattern.charAt(i+1) == '\'') {
  34.445 +                            segments[part].append(ch);  // handle doubles
  34.446 +                            ++i;
  34.447 +                        } else {
  34.448 +                            inQuote = !inQuote;
  34.449 +                        }
  34.450 +                    } else if (ch == '{' && !inQuote) {
  34.451 +                        part = SEG_INDEX;
  34.452 +                        if (segments[SEG_INDEX] == null) {
  34.453 +                            segments[SEG_INDEX] = new StringBuilder();
  34.454 +                        }
  34.455 +                    } else {
  34.456 +                        segments[part].append(ch);
  34.457 +                    }
  34.458 +                } else  {
  34.459 +                    if (inQuote) {              // just copy quotes in parts
  34.460 +                        segments[part].append(ch);
  34.461 +                        if (ch == '\'') {
  34.462 +                            inQuote = false;
  34.463 +                        }
  34.464 +                    } else {
  34.465 +                        switch (ch) {
  34.466 +                        case ',':
  34.467 +                            if (part < SEG_MODIFIER) {
  34.468 +                                if (segments[++part] == null) {
  34.469 +                                    segments[part] = new StringBuilder();
  34.470 +                                }
  34.471 +                            } else {
  34.472 +                                segments[part].append(ch);
  34.473 +                            }
  34.474 +                            break;
  34.475 +                        case '{':
  34.476 +                            ++braceStack;
  34.477 +                            segments[part].append(ch);
  34.478 +                            break;
  34.479 +                        case '}':
  34.480 +                            if (braceStack == 0) {
  34.481 +                                part = SEG_RAW;
  34.482 +                                makeFormat(i, formatNumber, segments);
  34.483 +                                formatNumber++;
  34.484 +                                // throw away other segments
  34.485 +                                segments[SEG_INDEX] = null;
  34.486 +                                segments[SEG_TYPE] = null;
  34.487 +                                segments[SEG_MODIFIER] = null;
  34.488 +                            } else {
  34.489 +                                --braceStack;
  34.490 +                                segments[part].append(ch);
  34.491 +                            }
  34.492 +                            break;
  34.493 +                        case ' ':
  34.494 +                            // Skip any leading space chars for SEG_TYPE.
  34.495 +                            if (part != SEG_TYPE || segments[SEG_TYPE].length() > 0) {
  34.496 +                                segments[part].append(ch);
  34.497 +                            }
  34.498 +                            break;
  34.499 +                        case '\'':
  34.500 +                            inQuote = true;
  34.501 +                            // fall through, so we keep quotes in other parts
  34.502 +                        default:
  34.503 +                            segments[part].append(ch);
  34.504 +                            break;
  34.505 +                        }
  34.506 +                    }
  34.507 +                }
  34.508 +            }
  34.509 +            if (braceStack == 0 && part != 0) {
  34.510 +                maxOffset = -1;
  34.511 +                throw new IllegalArgumentException("Unmatched braces in the pattern.");
  34.512 +            }
  34.513 +            this.pattern = segments[0].toString();
  34.514 +    }
  34.515 +
  34.516 +
  34.517 +    /**
  34.518 +     * Returns a pattern representing the current state of the message format.
  34.519 +     * The string is constructed from internal information and therefore
  34.520 +     * does not necessarily equal the previously applied pattern.
  34.521 +     *
  34.522 +     * @return a pattern representing the current state of the message format
  34.523 +     */
  34.524 +    public String toPattern() {
  34.525 +        // later, make this more extensible
  34.526 +        int lastOffset = 0;
  34.527 +        StringBuilder result = new StringBuilder();
  34.528 +        for (int i = 0; i <= maxOffset; ++i) {
  34.529 +            copyAndFixQuotes(pattern, lastOffset, offsets[i], result);
  34.530 +            lastOffset = offsets[i];
  34.531 +            result.append('{').append(argumentNumbers[i]);
  34.532 +            Format fmt = formats[i];
  34.533 +            if (fmt == null) {
  34.534 +                // do nothing, string format
  34.535 +            } else if (fmt instanceof NumberFormat) {
  34.536 +                if (fmt.equals(NumberFormat.getInstance(locale))) {
  34.537 +                    result.append(",number");
  34.538 +                } else if (fmt.equals(NumberFormat.getCurrencyInstance(locale))) {
  34.539 +                    result.append(",number,currency");
  34.540 +                } else if (fmt.equals(NumberFormat.getPercentInstance(locale))) {
  34.541 +                    result.append(",number,percent");
  34.542 +                } else if (fmt.equals(NumberFormat.getIntegerInstance(locale))) {
  34.543 +                    result.append(",number,integer");
  34.544 +                } else {
  34.545 +                    if (fmt instanceof DecimalFormat) {
  34.546 +                        result.append(",number,").append(((DecimalFormat)fmt).toPattern());
  34.547 +                    } else if (fmt instanceof ChoiceFormat) {
  34.548 +                        result.append(",choice,").append(((ChoiceFormat)fmt).toPattern());
  34.549 +                    } else {
  34.550 +                        // UNKNOWN
  34.551 +                    }
  34.552 +                }
  34.553 +            } else if (fmt instanceof DateFormat) {
  34.554 +                int index;
  34.555 +                for (index = MODIFIER_DEFAULT; index < DATE_TIME_MODIFIERS.length; index++) {
  34.556 +                    DateFormat df = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[index],
  34.557 +                                                               locale);
  34.558 +                    if (fmt.equals(df)) {
  34.559 +                        result.append(",date");
  34.560 +                        break;
  34.561 +                    }
  34.562 +                    df = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[index],
  34.563 +                                                    locale);
  34.564 +                    if (fmt.equals(df)) {
  34.565 +                        result.append(",time");
  34.566 +                        break;
  34.567 +                    }
  34.568 +                }
  34.569 +                if (index >= DATE_TIME_MODIFIERS.length) {
  34.570 +                    if (fmt instanceof SimpleDateFormat) {
  34.571 +                        result.append(",date,").append(((SimpleDateFormat)fmt).toPattern());
  34.572 +                    } else {
  34.573 +                        // UNKNOWN
  34.574 +                    }
  34.575 +                } else if (index != MODIFIER_DEFAULT) {
  34.576 +                    result.append(',').append(DATE_TIME_MODIFIER_KEYWORDS[index]);
  34.577 +                }
  34.578 +            } else {
  34.579 +                //result.append(", unknown");
  34.580 +            }
  34.581 +            result.append('}');
  34.582 +        }
  34.583 +        copyAndFixQuotes(pattern, lastOffset, pattern.length(), result);
  34.584 +        return result.toString();
  34.585 +    }
  34.586 +
  34.587 +    /**
  34.588 +     * Sets the formats to use for the values passed into
  34.589 +     * <code>format</code> methods or returned from <code>parse</code>
  34.590 +     * methods. The indices of elements in <code>newFormats</code>
  34.591 +     * correspond to the argument indices used in the previously set
  34.592 +     * pattern string.
  34.593 +     * The order of formats in <code>newFormats</code> thus corresponds to
  34.594 +     * the order of elements in the <code>arguments</code> array passed
  34.595 +     * to the <code>format</code> methods or the result array returned
  34.596 +     * by the <code>parse</code> methods.
  34.597 +     * <p>
  34.598 +     * If an argument index is used for more than one format element
  34.599 +     * in the pattern string, then the corresponding new format is used
  34.600 +     * for all such format elements. If an argument index is not used
  34.601 +     * for any format element in the pattern string, then the
  34.602 +     * corresponding new format is ignored. If fewer formats are provided
  34.603 +     * than needed, then only the formats for argument indices less
  34.604 +     * than <code>newFormats.length</code> are replaced.
  34.605 +     *
  34.606 +     * @param newFormats the new formats to use
  34.607 +     * @exception NullPointerException if <code>newFormats</code> is null
  34.608 +     * @since 1.4
  34.609 +     */
  34.610 +    public void setFormatsByArgumentIndex(Format[] newFormats) {
  34.611 +        for (int i = 0; i <= maxOffset; i++) {
  34.612 +            int j = argumentNumbers[i];
  34.613 +            if (j < newFormats.length) {
  34.614 +                formats[i] = newFormats[j];
  34.615 +            }
  34.616 +        }
  34.617 +    }
  34.618 +
  34.619 +    /**
  34.620 +     * Sets the formats to use for the format elements in the
  34.621 +     * previously set pattern string.
  34.622 +     * The order of formats in <code>newFormats</code> corresponds to
  34.623 +     * the order of format elements in the pattern string.
  34.624 +     * <p>
  34.625 +     * If more formats are provided than needed by the pattern string,
  34.626 +     * the remaining ones are ignored. If fewer formats are provided
  34.627 +     * than needed, then only the first <code>newFormats.length</code>
  34.628 +     * formats are replaced.
  34.629 +     * <p>
  34.630 +     * Since the order of format elements in a pattern string often
  34.631 +     * changes during localization, it is generally better to use the
  34.632 +     * {@link #setFormatsByArgumentIndex setFormatsByArgumentIndex}
  34.633 +     * method, which assumes an order of formats corresponding to the
  34.634 +     * order of elements in the <code>arguments</code> array passed to
  34.635 +     * the <code>format</code> methods or the result array returned by
  34.636 +     * the <code>parse</code> methods.
  34.637 +     *
  34.638 +     * @param newFormats the new formats to use
  34.639 +     * @exception NullPointerException if <code>newFormats</code> is null
  34.640 +     */
  34.641 +    public void setFormats(Format[] newFormats) {
  34.642 +        int runsToCopy = newFormats.length;
  34.643 +        if (runsToCopy > maxOffset + 1) {
  34.644 +            runsToCopy = maxOffset + 1;
  34.645 +        }
  34.646 +        for (int i = 0; i < runsToCopy; i++) {
  34.647 +            formats[i] = newFormats[i];
  34.648 +        }
  34.649 +    }
  34.650 +
  34.651 +    /**
  34.652 +     * Sets the format to use for the format elements within the
  34.653 +     * previously set pattern string that use the given argument
  34.654 +     * index.
  34.655 +     * The argument index is part of the format element definition and
  34.656 +     * represents an index into the <code>arguments</code> array passed
  34.657 +     * to the <code>format</code> methods or the result array returned
  34.658 +     * by the <code>parse</code> methods.
  34.659 +     * <p>
  34.660 +     * If the argument index is used for more than one format element
  34.661 +     * in the pattern string, then the new format is used for all such
  34.662 +     * format elements. If the argument index is not used for any format
  34.663 +     * element in the pattern string, then the new format is ignored.
  34.664 +     *
  34.665 +     * @param argumentIndex the argument index for which to use the new format
  34.666 +     * @param newFormat the new format to use
  34.667 +     * @since 1.4
  34.668 +     */
  34.669 +    public void setFormatByArgumentIndex(int argumentIndex, Format newFormat) {
  34.670 +        for (int j = 0; j <= maxOffset; j++) {
  34.671 +            if (argumentNumbers[j] == argumentIndex) {
  34.672 +                formats[j] = newFormat;
  34.673 +            }
  34.674 +        }
  34.675 +    }
  34.676 +
  34.677 +    /**
  34.678 +     * Sets the format to use for the format element with the given
  34.679 +     * format element index within the previously set pattern string.
  34.680 +     * The format element index is the zero-based number of the format
  34.681 +     * element counting from the start of the pattern string.
  34.682 +     * <p>
  34.683 +     * Since the order of format elements in a pattern string often
  34.684 +     * changes during localization, it is generally better to use the
  34.685 +     * {@link #setFormatByArgumentIndex setFormatByArgumentIndex}
  34.686 +     * method, which accesses format elements based on the argument
  34.687 +     * index they specify.
  34.688 +     *
  34.689 +     * @param formatElementIndex the index of a format element within the pattern
  34.690 +     * @param newFormat the format to use for the specified format element
  34.691 +     * @exception ArrayIndexOutOfBoundsException if {@code formatElementIndex} is equal to or
  34.692 +     *            larger than the number of format elements in the pattern string
  34.693 +     */
  34.694 +    public void setFormat(int formatElementIndex, Format newFormat) {
  34.695 +        formats[formatElementIndex] = newFormat;
  34.696 +    }
  34.697 +
  34.698 +    /**
  34.699 +     * Gets the formats used for the values passed into
  34.700 +     * <code>format</code> methods or returned from <code>parse</code>
  34.701 +     * methods. The indices of elements in the returned array
  34.702 +     * correspond to the argument indices used in the previously set
  34.703 +     * pattern string.
  34.704 +     * The order of formats in the returned array thus corresponds to
  34.705 +     * the order of elements in the <code>arguments</code> array passed
  34.706 +     * to the <code>format</code> methods or the result array returned
  34.707 +     * by the <code>parse</code> methods.
  34.708 +     * <p>
  34.709 +     * If an argument index is used for more than one format element
  34.710 +     * in the pattern string, then the format used for the last such
  34.711 +     * format element is returned in the array. If an argument index
  34.712 +     * is not used for any format element in the pattern string, then
  34.713 +     * null is returned in the array.
  34.714 +     *
  34.715 +     * @return the formats used for the arguments within the pattern
  34.716 +     * @since 1.4
  34.717 +     */
  34.718 +    public Format[] getFormatsByArgumentIndex() {
  34.719 +        int maximumArgumentNumber = -1;
  34.720 +        for (int i = 0; i <= maxOffset; i++) {
  34.721 +            if (argumentNumbers[i] > maximumArgumentNumber) {
  34.722 +                maximumArgumentNumber = argumentNumbers[i];
  34.723 +            }
  34.724 +        }
  34.725 +        Format[] resultArray = new Format[maximumArgumentNumber + 1];
  34.726 +        for (int i = 0; i <= maxOffset; i++) {
  34.727 +            resultArray[argumentNumbers[i]] = formats[i];
  34.728 +        }
  34.729 +        return resultArray;
  34.730 +    }
  34.731 +
  34.732 +    /**
  34.733 +     * Gets the formats used for the format elements in the
  34.734 +     * previously set pattern string.
  34.735 +     * The order of formats in the returned array corresponds to
  34.736 +     * the order of format elements in the pattern string.
  34.737 +     * <p>
  34.738 +     * Since the order of format elements in a pattern string often
  34.739 +     * changes during localization, it's generally better to use the
  34.740 +     * {@link #getFormatsByArgumentIndex getFormatsByArgumentIndex}
  34.741 +     * method, which assumes an order of formats corresponding to the
  34.742 +     * order of elements in the <code>arguments</code> array passed to
  34.743 +     * the <code>format</code> methods or the result array returned by
  34.744 +     * the <code>parse</code> methods.
  34.745 +     *
  34.746 +     * @return the formats used for the format elements in the pattern
  34.747 +     */
  34.748 +    public Format[] getFormats() {
  34.749 +        Format[] resultArray = new Format[maxOffset + 1];
  34.750 +        System.arraycopy(formats, 0, resultArray, 0, maxOffset + 1);
  34.751 +        return resultArray;
  34.752 +    }
  34.753 +
  34.754 +    /**
  34.755 +     * Formats an array of objects and appends the <code>MessageFormat</code>'s
  34.756 +     * pattern, with format elements replaced by the formatted objects, to the
  34.757 +     * provided <code>StringBuffer</code>.
  34.758 +     * <p>
  34.759 +     * The text substituted for the individual format elements is derived from
  34.760 +     * the current subformat of the format element and the
  34.761 +     * <code>arguments</code> element at the format element's argument index
  34.762 +     * as indicated by the first matching line of the following table. An
  34.763 +     * argument is <i>unavailable</i> if <code>arguments</code> is
  34.764 +     * <code>null</code> or has fewer than argumentIndex+1 elements.
  34.765 +     * <p>
  34.766 +     * <table border=1 summary="Examples of subformat,argument,and formatted text">
  34.767 +     *    <tr>
  34.768 +     *       <th>Subformat
  34.769 +     *       <th>Argument
  34.770 +     *       <th>Formatted Text
  34.771 +     *    <tr>
  34.772 +     *       <td><i>any</i>
  34.773 +     *       <td><i>unavailable</i>
  34.774 +     *       <td><code>"{" + argumentIndex + "}"</code>
  34.775 +     *    <tr>
  34.776 +     *       <td><i>any</i>
  34.777 +     *       <td><code>null</code>
  34.778 +     *       <td><code>"null"</code>
  34.779 +     *    <tr>
  34.780 +     *       <td><code>instanceof ChoiceFormat</code>
  34.781 +     *       <td><i>any</i>
  34.782 +     *       <td><code>subformat.format(argument).indexOf('{') >= 0 ?<br>
  34.783 +     *           (new MessageFormat(subformat.format(argument), getLocale())).format(argument) :
  34.784 +     *           subformat.format(argument)</code>
  34.785 +     *    <tr>
  34.786 +     *       <td><code>!= null</code>
  34.787 +     *       <td><i>any</i>
  34.788 +     *       <td><code>subformat.format(argument)</code>
  34.789 +     *    <tr>
  34.790 +     *       <td><code>null</code>
  34.791 +     *       <td><code>instanceof Number</code>
  34.792 +     *       <td><code>NumberFormat.getInstance(getLocale()).format(argument)</code>
  34.793 +     *    <tr>
  34.794 +     *       <td><code>null</code>
  34.795 +     *       <td><code>instanceof Date</code>
  34.796 +     *       <td><code>DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, getLocale()).format(argument)</code>
  34.797 +     *    <tr>
  34.798 +     *       <td><code>null</code>
  34.799 +     *       <td><code>instanceof String</code>
  34.800 +     *       <td><code>argument</code>
  34.801 +     *    <tr>
  34.802 +     *       <td><code>null</code>
  34.803 +     *       <td><i>any</i>
  34.804 +     *       <td><code>argument.toString()</code>
  34.805 +     * </table>
  34.806 +     * <p>
  34.807 +     * If <code>pos</code> is non-null, and refers to
  34.808 +     * <code>Field.ARGUMENT</code>, the location of the first formatted
  34.809 +     * string will be returned.
  34.810 +     *
  34.811 +     * @param arguments an array of objects to be formatted and substituted.
  34.812 +     * @param result where text is appended.
  34.813 +     * @param pos On input: an alignment field, if desired.
  34.814 +     *            On output: the offsets of the alignment field.
  34.815 +     * @exception IllegalArgumentException if an argument in the
  34.816 +     *            <code>arguments</code> array is not of the type
  34.817 +     *            expected by the format element(s) that use it.
  34.818 +     */
  34.819 +    public final StringBuffer format(Object[] arguments, StringBuffer result,
  34.820 +                                     FieldPosition pos)
  34.821 +    {
  34.822 +        return subformat(arguments, result, pos, null);
  34.823 +    }
  34.824 +
  34.825 +    /**
  34.826 +     * Creates a MessageFormat with the given pattern and uses it
  34.827 +     * to format the given arguments. This is equivalent to
  34.828 +     * <blockquote>
  34.829 +     *     <code>(new {@link #MessageFormat(String) MessageFormat}(pattern)).{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
  34.830 +     * </blockquote>
  34.831 +     *
  34.832 +     * @exception IllegalArgumentException if the pattern is invalid,
  34.833 +     *            or if an argument in the <code>arguments</code> array
  34.834 +     *            is not of the type expected by the format element(s)
  34.835 +     *            that use it.
  34.836 +     */
  34.837 +    public static String format(String pattern, Object ... arguments) {
  34.838 +        MessageFormat temp = new MessageFormat(pattern);
  34.839 +        return temp.format(arguments);
  34.840 +    }
  34.841 +
  34.842 +    // Overrides
  34.843 +    /**
  34.844 +     * Formats an array of objects and appends the <code>MessageFormat</code>'s
  34.845 +     * pattern, with format elements replaced by the formatted objects, to the
  34.846 +     * provided <code>StringBuffer</code>.
  34.847 +     * This is equivalent to
  34.848 +     * <blockquote>
  34.849 +     *     <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}((Object[]) arguments, result, pos)</code>
  34.850 +     * </blockquote>
  34.851 +     *
  34.852 +     * @param arguments an array of objects to be formatted and substituted.
  34.853 +     * @param result where text is appended.
  34.854 +     * @param pos On input: an alignment field, if desired.
  34.855 +     *            On output: the offsets of the alignment field.
  34.856 +     * @exception IllegalArgumentException if an argument in the
  34.857 +     *            <code>arguments</code> array is not of the type
  34.858 +     *            expected by the format element(s) that use it.
  34.859 +     */
  34.860 +    public final StringBuffer format(Object arguments, StringBuffer result,
  34.861 +                                     FieldPosition pos)
  34.862 +    {
  34.863 +        return subformat((Object[]) arguments, result, pos, null);
  34.864 +    }
  34.865 +
  34.866 +    /**
  34.867 +     * Formats an array of objects and inserts them into the
  34.868 +     * <code>MessageFormat</code>'s pattern, producing an
  34.869 +     * <code>AttributedCharacterIterator</code>.
  34.870 +     * You can use the returned <code>AttributedCharacterIterator</code>
  34.871 +     * to build the resulting String, as well as to determine information
  34.872 +     * about the resulting String.
  34.873 +     * <p>
  34.874 +     * The text of the returned <code>AttributedCharacterIterator</code> is
  34.875 +     * the same that would be returned by
  34.876 +     * <blockquote>
  34.877 +     *     <code>{@link #format(java.lang.Object[], java.lang.StringBuffer, java.text.FieldPosition) format}(arguments, new StringBuffer(), null).toString()</code>
  34.878 +     * </blockquote>
  34.879 +     * <p>
  34.880 +     * In addition, the <code>AttributedCharacterIterator</code> contains at
  34.881 +     * least attributes indicating where text was generated from an
  34.882 +     * argument in the <code>arguments</code> array. The keys of these attributes are of
  34.883 +     * type <code>MessageFormat.Field</code>, their values are
  34.884 +     * <code>Integer</code> objects indicating the index in the <code>arguments</code>
  34.885 +     * array of the argument from which the text was generated.
  34.886 +     * <p>
  34.887 +     * The attributes/value from the underlying <code>Format</code>
  34.888 +     * instances that <code>MessageFormat</code> uses will also be
  34.889 +     * placed in the resulting <code>AttributedCharacterIterator</code>.
  34.890 +     * This allows you to not only find where an argument is placed in the
  34.891 +     * resulting String, but also which fields it contains in turn.
  34.892 +     *
  34.893 +     * @param arguments an array of objects to be formatted and substituted.
  34.894 +     * @return AttributedCharacterIterator describing the formatted value.
  34.895 +     * @exception NullPointerException if <code>arguments</code> is null.
  34.896 +     * @exception IllegalArgumentException if an argument in the
  34.897 +     *            <code>arguments</code> array is not of the type
  34.898 +     *            expected by the format element(s) that use it.
  34.899 +     * @since 1.4
  34.900 +     */
  34.901 +    public AttributedCharacterIterator formatToCharacterIterator(Object arguments) {
  34.902 +        StringBuffer result = new StringBuffer();
  34.903 +        ArrayList iterators = new ArrayList();
  34.904 +
  34.905 +        if (arguments == null) {
  34.906 +            throw new NullPointerException(
  34.907 +                   "formatToCharacterIterator must be passed non-null object");
  34.908 +        }
  34.909 +        subformat((Object[]) arguments, result, null, iterators);
  34.910 +        if (iterators.size() == 0) {
  34.911 +            return createAttributedCharacterIterator("");
  34.912 +        }
  34.913 +        return createAttributedCharacterIterator(
  34.914 +                     (AttributedCharacterIterator[])iterators.toArray(
  34.915 +                     new AttributedCharacterIterator[iterators.size()]));
  34.916 +    }
  34.917 +
  34.918 +    /**
  34.919 +     * Parses the string.
  34.920 +     *
  34.921 +     * <p>Caveats: The parse may fail in a number of circumstances.
  34.922 +     * For example:
  34.923 +     * <ul>
  34.924 +     * <li>If one of the arguments does not occur in the pattern.
  34.925 +     * <li>If the format of an argument loses information, such as
  34.926 +     *     with a choice format where a large number formats to "many".
  34.927 +     * <li>Does not yet handle recursion (where
  34.928 +     *     the substituted strings contain {n} references.)
  34.929 +     * <li>Will not always find a match (or the correct match)
  34.930 +     *     if some part of the parse is ambiguous.
  34.931 +     *     For example, if the pattern "{1},{2}" is used with the
  34.932 +     *     string arguments {"a,b", "c"}, it will format as "a,b,c".
  34.933 +     *     When the result is parsed, it will return {"a", "b,c"}.
  34.934 +     * <li>If a single argument is parsed more than once in the string,
  34.935 +     *     then the later parse wins.
  34.936 +     * </ul>
  34.937 +     * When the parse fails, use ParsePosition.getErrorIndex() to find out
  34.938 +     * where in the string the parsing failed.  The returned error
  34.939 +     * index is the starting offset of the sub-patterns that the string
  34.940 +     * is comparing with.  For example, if the parsing string "AAA {0} BBB"
  34.941 +     * is comparing against the pattern "AAD {0} BBB", the error index is
  34.942 +     * 0. When an error occurs, the call to this method will return null.
  34.943 +     * If the source is null, return an empty array.
  34.944 +     */
  34.945 +    public Object[] parse(String source, ParsePosition pos) {
  34.946 +        if (source == null) {
  34.947 +            Object[] empty = {};
  34.948 +            return empty;
  34.949 +        }
  34.950 +
  34.951 +        int maximumArgumentNumber = -1;
  34.952 +        for (int i = 0; i <= maxOffset; i++) {
  34.953 +            if (argumentNumbers[i] > maximumArgumentNumber) {
  34.954 +                maximumArgumentNumber = argumentNumbers[i];
  34.955 +            }
  34.956 +        }
  34.957 +        Object[] resultArray = new Object[maximumArgumentNumber + 1];
  34.958 +
  34.959 +        int patternOffset = 0;
  34.960 +        int sourceOffset = pos.index;
  34.961 +        ParsePosition tempStatus = new ParsePosition(0);
  34.962 +        for (int i = 0; i <= maxOffset; ++i) {
  34.963 +            // match up to format
  34.964 +            int len = offsets[i] - patternOffset;
  34.965 +            if (len == 0 || pattern.regionMatches(patternOffset,
  34.966 +                                                  source, sourceOffset, len)) {
  34.967 +                sourceOffset += len;
  34.968 +                patternOffset += len;
  34.969 +            } else {
  34.970 +                pos.errorIndex = sourceOffset;
  34.971 +                return null; // leave index as is to signal error
  34.972 +            }
  34.973 +
  34.974 +            // now use format
  34.975 +            if (formats[i] == null) {   // string format
  34.976 +                // if at end, use longest possible match
  34.977 +                // otherwise uses first match to intervening string
  34.978 +                // does NOT recursively try all possibilities
  34.979 +                int tempLength = (i != maxOffset) ? offsets[i+1] : pattern.length();
  34.980 +
  34.981 +                int next;
  34.982 +                if (patternOffset >= tempLength) {
  34.983 +                    next = source.length();
  34.984 +                }else{
  34.985 +                    next = source.indexOf(pattern.substring(patternOffset, tempLength),
  34.986 +                                          sourceOffset);
  34.987 +                }
  34.988 +
  34.989 +                if (next < 0) {
  34.990 +                    pos.errorIndex = sourceOffset;
  34.991 +                    return null; // leave index as is to signal error
  34.992 +                } else {
  34.993 +                    String strValue= source.substring(sourceOffset,next);
  34.994 +                    if (!strValue.equals("{"+argumentNumbers[i]+"}"))
  34.995 +                        resultArray[argumentNumbers[i]]
  34.996 +                            = source.substring(sourceOffset,next);
  34.997 +                    sourceOffset = next;
  34.998 +                }
  34.999 +            } else {
 34.1000 +                tempStatus.index = sourceOffset;
 34.1001 +                resultArray[argumentNumbers[i]]
 34.1002 +                    = formats[i].parseObject(source,tempStatus);
 34.1003 +                if (tempStatus.index == sourceOffset) {
 34.1004 +                    pos.errorIndex = sourceOffset;
 34.1005 +                    return null; // leave index as is to signal error
 34.1006 +                }
 34.1007 +                sourceOffset = tempStatus.index; // update
 34.1008 +            }
 34.1009 +        }
 34.1010 +        int len = pattern.length() - patternOffset;
 34.1011 +        if (len == 0 || pattern.regionMatches(patternOffset,
 34.1012 +                                              source, sourceOffset, len)) {
 34.1013 +            pos.index = sourceOffset + len;
 34.1014 +        } else {
 34.1015 +            pos.errorIndex = sourceOffset;
 34.1016 +            return null; // leave index as is to signal error
 34.1017 +        }
 34.1018 +        return resultArray;
 34.1019 +    }
 34.1020 +
 34.1021 +    /**
 34.1022 +     * Parses text from the beginning of the given string to produce an object
 34.1023 +     * array.
 34.1024 +     * The method may not use the entire text of the given string.
 34.1025 +     * <p>
 34.1026 +     * See the {@link #parse(String, ParsePosition)} method for more information
 34.1027 +     * on message parsing.
 34.1028 +     *
 34.1029 +     * @param source A <code>String</code> whose beginning should be parsed.
 34.1030 +     * @return An <code>Object</code> array parsed from the string.
 34.1031 +     * @exception ParseException if the beginning of the specified string
 34.1032 +     *            cannot be parsed.
 34.1033 +     */
 34.1034 +    public Object[] parse(String source) throws ParseException {
 34.1035 +        ParsePosition pos  = new ParsePosition(0);
 34.1036 +        Object[] result = parse(source, pos);
 34.1037 +        if (pos.index == 0)  // unchanged, returned object is null
 34.1038 +            throw new ParseException("MessageFormat parse error!", pos.errorIndex);
 34.1039 +
 34.1040 +        return result;
 34.1041 +    }
 34.1042 +
 34.1043 +    /**
 34.1044 +     * Parses text from a string to produce an object array.
 34.1045 +     * <p>
 34.1046 +     * The method attempts to parse text starting at the index given by
 34.1047 +     * <code>pos</code>.
 34.1048 +     * If parsing succeeds, then the index of <code>pos</code> is updated
 34.1049 +     * to the index after the last character used (parsing does not necessarily
 34.1050 +     * use all characters up to the end of the string), and the parsed
 34.1051 +     * object array is returned. The updated <code>pos</code> can be used to
 34.1052 +     * indicate the starting point for the next call to this method.
 34.1053 +     * If an error occurs, then the index of <code>pos</code> is not
 34.1054 +     * changed, the error index of <code>pos</code> is set to the index of
 34.1055 +     * the character where the error occurred, and null is returned.
 34.1056 +     * <p>
 34.1057 +     * See the {@link #parse(String, ParsePosition)} method for more information
 34.1058 +     * on message parsing.
 34.1059 +     *
 34.1060 +     * @param source A <code>String</code>, part of which should be parsed.
 34.1061 +     * @param pos A <code>ParsePosition</code> object with index and error
 34.1062 +     *            index information as described above.
 34.1063 +     * @return An <code>Object</code> array parsed from the string. In case of
 34.1064 +     *         error, returns null.
 34.1065 +     * @exception NullPointerException if <code>pos</code> is null.
 34.1066 +     */
 34.1067 +    public Object parseObject(String source, ParsePosition pos) {
 34.1068 +        return parse(source, pos);
 34.1069 +    }
 34.1070 +
 34.1071 +    /**
 34.1072 +     * Creates and returns a copy of this object.
 34.1073 +     *
 34.1074 +     * @return a clone of this instance.
 34.1075 +     */
 34.1076 +    public Object clone() {
 34.1077 +        MessageFormat other = (MessageFormat) super.clone();
 34.1078 +
 34.1079 +        // clone arrays. Can't do with utility because of bug in Cloneable
 34.1080 +        other.formats = (Format[]) formats.clone(); // shallow clone
 34.1081 +        for (int i = 0; i < formats.length; ++i) {
 34.1082 +            if (formats[i] != null)
 34.1083 +                other.formats[i] = (Format)formats[i].clone();
 34.1084 +        }
 34.1085 +        // for primitives or immutables, shallow clone is enough
 34.1086 +        other.offsets = (int[]) offsets.clone();
 34.1087 +        other.argumentNumbers = (int[]) argumentNumbers.clone();
 34.1088 +
 34.1089 +        return other;
 34.1090 +    }
 34.1091 +
 34.1092 +    /**
 34.1093 +     * Equality comparison between two message format objects
 34.1094 +     */
 34.1095 +    public boolean equals(Object obj) {
 34.1096 +        if (this == obj)                      // quick check
 34.1097 +            return true;
 34.1098 +        if (obj == null || getClass() != obj.getClass())
 34.1099 +            return false;
 34.1100 +        MessageFormat other = (MessageFormat) obj;
 34.1101 +        return (maxOffset == other.maxOffset
 34.1102 +                && pattern.equals(other.pattern)
 34.1103 +                && ((locale != null && locale.equals(other.locale))
 34.1104 +                 || (locale == null && other.locale == null))
 34.1105 +                && Arrays.equals(offsets,other.offsets)
 34.1106 +                && Arrays.equals(argumentNumbers,other.argumentNumbers)
 34.1107 +                && Arrays.equals(formats,other.formats));
 34.1108 +    }
 34.1109 +
 34.1110 +    /**
 34.1111 +     * Generates a hash code for the message format object.
 34.1112 +     */
 34.1113 +    public int hashCode() {
 34.1114 +        return pattern.hashCode(); // enough for reasonable distribution
 34.1115 +    }
 34.1116 +
 34.1117 +
 34.1118 +    /**
 34.1119 +     * Defines constants that are used as attribute keys in the
 34.1120 +     * <code>AttributedCharacterIterator</code> returned
 34.1121 +     * from <code>MessageFormat.formatToCharacterIterator</code>.
 34.1122 +     *
 34.1123 +     * @since 1.4
 34.1124 +     */
 34.1125 +    public static class Field extends Format.Field {
 34.1126 +
 34.1127 +        // Proclaim serial compatibility with 1.4 FCS
 34.1128 +        private static final long serialVersionUID = 7899943957617360810L;
 34.1129 +
 34.1130 +        /**
 34.1131 +         * Creates a Field with the specified name.
 34.1132 +         *
 34.1133 +         * @param name Name of the attribute
 34.1134 +         */
 34.1135 +        protected Field(String name) {
 34.1136 +            super(name);
 34.1137 +        }
 34.1138 +
 34.1139 +        /**
 34.1140 +         * Resolves instances being deserialized to the predefined constants.
 34.1141 +         *
 34.1142 +         * @throws InvalidObjectException if the constant could not be
 34.1143 +         *         resolved.
 34.1144 +         * @return resolved MessageFormat.Field constant
 34.1145 +         */
 34.1146 +        protected Object readResolve() throws InvalidObjectException {
 34.1147 +            if (this.getClass() != MessageFormat.Field.class) {
 34.1148 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
 34.1149 +            }
 34.1150 +
 34.1151 +            return ARGUMENT;
 34.1152 +        }
 34.1153 +
 34.1154 +        //
 34.1155 +        // The constants
 34.1156 +        //
 34.1157 +
 34.1158 +        /**
 34.1159 +         * Constant identifying a portion of a message that was generated
 34.1160 +         * from an argument passed into <code>formatToCharacterIterator</code>.
 34.1161 +         * The value associated with the key will be an <code>Integer</code>
 34.1162 +         * indicating the index in the <code>arguments</code> array of the
 34.1163 +         * argument from which the text was generated.
 34.1164 +         */
 34.1165 +        public final static Field ARGUMENT =
 34.1166 +                           new Field("message argument field");
 34.1167 +    }
 34.1168 +
 34.1169 +    // ===========================privates============================
 34.1170 +
 34.1171 +    /**
 34.1172 +     * The locale to use for formatting numbers and dates.
 34.1173 +     * @serial
 34.1174 +     */
 34.1175 +    private Locale locale;
 34.1176 +
 34.1177 +    /**
 34.1178 +     * The string that the formatted values are to be plugged into.  In other words, this
 34.1179 +     * is the pattern supplied on construction with all of the {} expressions taken out.
 34.1180 +     * @serial
 34.1181 +     */
 34.1182 +    private String pattern = "";
 34.1183 +
 34.1184 +    /** The initially expected number of subformats in the format */
 34.1185 +    private static final int INITIAL_FORMATS = 10;
 34.1186 +
 34.1187 +    /**
 34.1188 +     * An array of formatters, which are used to format the arguments.
 34.1189 +     * @serial
 34.1190 +     */
 34.1191 +    private Format[] formats = new Format[INITIAL_FORMATS];
 34.1192 +
 34.1193 +    /**
 34.1194 +     * The positions where the results of formatting each argument are to be inserted
 34.1195 +     * into the pattern.
 34.1196 +     * @serial
 34.1197 +     */
 34.1198 +    private int[] offsets = new int[INITIAL_FORMATS];
 34.1199 +
 34.1200 +    /**
 34.1201 +     * The argument numbers corresponding to each formatter.  (The formatters are stored
 34.1202 +     * in the order they occur in the pattern, not in the order in which the arguments
 34.1203 +     * are specified.)
 34.1204 +     * @serial
 34.1205 +     */
 34.1206 +    private int[] argumentNumbers = new int[INITIAL_FORMATS];
 34.1207 +
 34.1208 +    /**
 34.1209 +     * One less than the number of entries in <code>offsets</code>.  Can also be thought of
 34.1210 +     * as the index of the highest-numbered element in <code>offsets</code> that is being used.
 34.1211 +     * All of these arrays should have the same number of elements being used as <code>offsets</code>
 34.1212 +     * does, and so this variable suffices to tell us how many entries are in all of them.
 34.1213 +     * @serial
 34.1214 +     */
 34.1215 +    private int maxOffset = -1;
 34.1216 +
 34.1217 +    /**
 34.1218 +     * Internal routine used by format. If <code>characterIterators</code> is
 34.1219 +     * non-null, AttributedCharacterIterator will be created from the
 34.1220 +     * subformats as necessary. If <code>characterIterators</code> is null
 34.1221 +     * and <code>fp</code> is non-null and identifies
 34.1222 +     * <code>Field.MESSAGE_ARGUMENT</code>, the location of
 34.1223 +     * the first replaced argument will be set in it.
 34.1224 +     *
 34.1225 +     * @exception IllegalArgumentException if an argument in the
 34.1226 +     *            <code>arguments</code> array is not of the type
 34.1227 +     *            expected by the format element(s) that use it.
 34.1228 +     */
 34.1229 +    private StringBuffer subformat(Object[] arguments, StringBuffer result,
 34.1230 +                                   FieldPosition fp, List characterIterators) {
 34.1231 +        // note: this implementation assumes a fast substring & index.
 34.1232 +        // if this is not true, would be better to append chars one by one.
 34.1233 +        int lastOffset = 0;
 34.1234 +        int last = result.length();
 34.1235 +        for (int i = 0; i <= maxOffset; ++i) {
 34.1236 +            result.append(pattern.substring(lastOffset, offsets[i]));
 34.1237 +            lastOffset = offsets[i];
 34.1238 +            int argumentNumber = argumentNumbers[i];
 34.1239 +            if (arguments == null || argumentNumber >= arguments.length) {
 34.1240 +                result.append('{').append(argumentNumber).append('}');
 34.1241 +                continue;
 34.1242 +            }
 34.1243 +            // int argRecursion = ((recursionProtection >> (argumentNumber*2)) & 0x3);
 34.1244 +            if (false) { // if (argRecursion == 3){
 34.1245 +                // prevent loop!!!
 34.1246 +                result.append('\uFFFD');
 34.1247 +            } else {
 34.1248 +                Object obj = arguments[argumentNumber];
 34.1249 +                String arg = null;
 34.1250 +                Format subFormatter = null;
 34.1251 +                if (obj == null) {
 34.1252 +                    arg = "null";
 34.1253 +                } else if (formats[i] != null) {
 34.1254 +                    subFormatter = formats[i];
 34.1255 +                    if (subFormatter instanceof ChoiceFormat) {
 34.1256 +                        arg = formats[i].format(obj);
 34.1257 +                        if (arg.indexOf('{') >= 0) {
 34.1258 +                            subFormatter = new MessageFormat(arg, locale);
 34.1259 +                            obj = arguments;
 34.1260 +                            arg = null;
 34.1261 +                        }
 34.1262 +                    }
 34.1263 +                } else if (obj instanceof Number) {
 34.1264 +                    // format number if can
 34.1265 +                    subFormatter = NumberFormat.getInstance(locale);
 34.1266 +                } else if (obj instanceof Date) {
 34.1267 +                    // format a Date if can
 34.1268 +                    subFormatter = DateFormat.getDateTimeInstance(
 34.1269 +                             DateFormat.SHORT, DateFormat.SHORT, locale);//fix
 34.1270 +                } else if (obj instanceof String) {
 34.1271 +                    arg = (String) obj;
 34.1272 +
 34.1273 +                } else {
 34.1274 +                    arg = obj.toString();
 34.1275 +                    if (arg == null) arg = "null";
 34.1276 +                }
 34.1277 +
 34.1278 +                // At this point we are in two states, either subFormatter
 34.1279 +                // is non-null indicating we should format obj using it,
 34.1280 +                // or arg is non-null and we should use it as the value.
 34.1281 +
 34.1282 +                if (characterIterators != null) {
 34.1283 +                    // If characterIterators is non-null, it indicates we need
 34.1284 +                    // to get the CharacterIterator from the child formatter.
 34.1285 +                    if (last != result.length()) {
 34.1286 +                        characterIterators.add(
 34.1287 +                            createAttributedCharacterIterator(result.substring
 34.1288 +                                                              (last)));
 34.1289 +                        last = result.length();
 34.1290 +                    }
 34.1291 +                    if (subFormatter != null) {
 34.1292 +                        AttributedCharacterIterator subIterator =
 34.1293 +                                   subFormatter.formatToCharacterIterator(obj);
 34.1294 +
 34.1295 +                        append(result, subIterator);
 34.1296 +                        if (last != result.length()) {
 34.1297 +                            characterIterators.add(
 34.1298 +                                         createAttributedCharacterIterator(
 34.1299 +                                         subIterator, Field.ARGUMENT,
 34.1300 +                                         Integer.valueOf(argumentNumber)));
 34.1301 +                            last = result.length();
 34.1302 +                        }
 34.1303 +                        arg = null;
 34.1304 +                    }
 34.1305 +                    if (arg != null && arg.length() > 0) {
 34.1306 +                        result.append(arg);
 34.1307 +                        characterIterators.add(
 34.1308 +                                 createAttributedCharacterIterator(
 34.1309 +                                 arg, Field.ARGUMENT,
 34.1310 +                                 Integer.valueOf(argumentNumber)));
 34.1311 +                        last = result.length();
 34.1312 +                    }
 34.1313 +                }
 34.1314 +                else {
 34.1315 +                    if (subFormatter != null) {
 34.1316 +                        arg = subFormatter.format(obj);
 34.1317 +                    }
 34.1318 +                    last = result.length();
 34.1319 +                    result.append(arg);
 34.1320 +                    if (i == 0 && fp != null && Field.ARGUMENT.equals(
 34.1321 +                                  fp.getFieldAttribute())) {
 34.1322 +                        fp.setBeginIndex(last);
 34.1323 +                        fp.setEndIndex(result.length());
 34.1324 +                    }
 34.1325 +                    last = result.length();
 34.1326 +                }
 34.1327 +            }
 34.1328 +        }
 34.1329 +        result.append(pattern.substring(lastOffset, pattern.length()));
 34.1330 +        if (characterIterators != null && last != result.length()) {
 34.1331 +            characterIterators.add(createAttributedCharacterIterator(
 34.1332 +                                   result.substring(last)));
 34.1333 +        }
 34.1334 +        return result;
 34.1335 +    }
 34.1336 +
 34.1337 +    /**
 34.1338 +     * Convenience method to append all the characters in
 34.1339 +     * <code>iterator</code> to the StringBuffer <code>result</code>.
 34.1340 +     */
 34.1341 +    private void append(StringBuffer result, CharacterIterator iterator) {
 34.1342 +        if (iterator.first() != CharacterIterator.DONE) {
 34.1343 +            char aChar;
 34.1344 +
 34.1345 +            result.append(iterator.first());
 34.1346 +            while ((aChar = iterator.next()) != CharacterIterator.DONE) {
 34.1347 +                result.append(aChar);
 34.1348 +            }
 34.1349 +        }
 34.1350 +    }
 34.1351 +
 34.1352 +    // Indices for segments
 34.1353 +    private static final int SEG_RAW      = 0;
 34.1354 +    private static final int SEG_INDEX    = 1;
 34.1355 +    private static final int SEG_TYPE     = 2;
 34.1356 +    private static final int SEG_MODIFIER = 3; // modifier or subformat
 34.1357 +
 34.1358 +    // Indices for type keywords
 34.1359 +    private static final int TYPE_NULL    = 0;
 34.1360 +    private static final int TYPE_NUMBER  = 1;
 34.1361 +    private static final int TYPE_DATE    = 2;
 34.1362 +    private static final int TYPE_TIME    = 3;
 34.1363 +    private static final int TYPE_CHOICE  = 4;
 34.1364 +
 34.1365 +    private static final String[] TYPE_KEYWORDS = {
 34.1366 +        "",
 34.1367 +        "number",
 34.1368 +        "date",
 34.1369 +        "time",
 34.1370 +        "choice"
 34.1371 +    };
 34.1372 +
 34.1373 +    // Indices for number modifiers
 34.1374 +    private static final int MODIFIER_DEFAULT  = 0; // common in number and date-time
 34.1375 +    private static final int MODIFIER_CURRENCY = 1;
 34.1376 +    private static final int MODIFIER_PERCENT  = 2;
 34.1377 +    private static final int MODIFIER_INTEGER  = 3;
 34.1378 +
 34.1379 +    private static final String[] NUMBER_MODIFIER_KEYWORDS = {
 34.1380 +        "",
 34.1381 +        "currency",
 34.1382 +        "percent",
 34.1383 +        "integer"
 34.1384 +    };
 34.1385 +
 34.1386 +    // Indices for date-time modifiers
 34.1387 +    private static final int MODIFIER_SHORT   = 1;
 34.1388 +    private static final int MODIFIER_MEDIUM  = 2;
 34.1389 +    private static final int MODIFIER_LONG    = 3;
 34.1390 +    private static final int MODIFIER_FULL    = 4;
 34.1391 +
 34.1392 +    private static final String[] DATE_TIME_MODIFIER_KEYWORDS = {
 34.1393 +        "",
 34.1394 +        "short",
 34.1395 +        "medium",
 34.1396 +        "long",
 34.1397 +        "full"
 34.1398 +    };
 34.1399 +
 34.1400 +    // Date-time style values corresponding to the date-time modifiers.
 34.1401 +    private static final int[] DATE_TIME_MODIFIERS = {
 34.1402 +        DateFormat.DEFAULT,
 34.1403 +        DateFormat.SHORT,
 34.1404 +        DateFormat.MEDIUM,
 34.1405 +        DateFormat.LONG,
 34.1406 +        DateFormat.FULL,
 34.1407 +    };
 34.1408 +
 34.1409 +    private void makeFormat(int position, int offsetNumber,
 34.1410 +                            StringBuilder[] textSegments)
 34.1411 +    {
 34.1412 +        String[] segments = new String[textSegments.length];
 34.1413 +        for (int i = 0; i < textSegments.length; i++) {
 34.1414 +            StringBuilder oneseg = textSegments[i];
 34.1415 +            segments[i] = (oneseg != null) ? oneseg.toString() : "";
 34.1416 +        }
 34.1417 +
 34.1418 +        // get the argument number
 34.1419 +        int argumentNumber;
 34.1420 +        try {
 34.1421 +            argumentNumber = Integer.parseInt(segments[SEG_INDEX]); // always unlocalized!
 34.1422 +        } catch (NumberFormatException e) {
 34.1423 +            throw new IllegalArgumentException("can't parse argument number: "
 34.1424 +                                               + segments[SEG_INDEX], e);
 34.1425 +        }
 34.1426 +        if (argumentNumber < 0) {
 34.1427 +            throw new IllegalArgumentException("negative argument number: "
 34.1428 +                                               + argumentNumber);
 34.1429 +        }
 34.1430 +
 34.1431 +        // resize format information arrays if necessary
 34.1432 +        if (offsetNumber >= formats.length) {
 34.1433 +            int newLength = formats.length * 2;
 34.1434 +            Format[] newFormats = new Format[newLength];
 34.1435 +            int[] newOffsets = new int[newLength];
 34.1436 +            int[] newArgumentNumbers = new int[newLength];
 34.1437 +            System.arraycopy(formats, 0, newFormats, 0, maxOffset + 1);
 34.1438 +            System.arraycopy(offsets, 0, newOffsets, 0, maxOffset + 1);
 34.1439 +            System.arraycopy(argumentNumbers, 0, newArgumentNumbers, 0, maxOffset + 1);
 34.1440 +            formats = newFormats;
 34.1441 +            offsets = newOffsets;
 34.1442 +            argumentNumbers = newArgumentNumbers;
 34.1443 +        }
 34.1444 +        int oldMaxOffset = maxOffset;
 34.1445 +        maxOffset = offsetNumber;
 34.1446 +        offsets[offsetNumber] = segments[SEG_RAW].length();
 34.1447 +        argumentNumbers[offsetNumber] = argumentNumber;
 34.1448 +
 34.1449 +        // now get the format
 34.1450 +        Format newFormat = null;
 34.1451 +        if (segments[SEG_TYPE].length() != 0) {
 34.1452 +            int type = findKeyword(segments[SEG_TYPE], TYPE_KEYWORDS);
 34.1453 +            switch (type) {
 34.1454 +            case TYPE_NULL:
 34.1455 +                // Type "" is allowed. e.g., "{0,}", "{0,,}", and "{0,,#}"
 34.1456 +                // are treated as "{0}".
 34.1457 +                break;
 34.1458 +
 34.1459 +            case TYPE_NUMBER:
 34.1460 +                switch (findKeyword(segments[SEG_MODIFIER], NUMBER_MODIFIER_KEYWORDS)) {
 34.1461 +                case MODIFIER_DEFAULT:
 34.1462 +                    newFormat = NumberFormat.getInstance(locale);
 34.1463 +                    break;
 34.1464 +                case MODIFIER_CURRENCY:
 34.1465 +                    newFormat = NumberFormat.getCurrencyInstance(locale);
 34.1466 +                    break;
 34.1467 +                case MODIFIER_PERCENT:
 34.1468 +                    newFormat = NumberFormat.getPercentInstance(locale);
 34.1469 +                    break;
 34.1470 +                case MODIFIER_INTEGER:
 34.1471 +                    newFormat = NumberFormat.getIntegerInstance(locale);
 34.1472 +                    break;
 34.1473 +                default: // DecimalFormat pattern
 34.1474 +                    try {
 34.1475 +                        newFormat = new DecimalFormat(segments[SEG_MODIFIER],
 34.1476 +                                                      DecimalFormatSymbols.getInstance(locale));
 34.1477 +                    } catch (IllegalArgumentException e) {
 34.1478 +                        maxOffset = oldMaxOffset;
 34.1479 +                        throw e;
 34.1480 +                    }
 34.1481 +                    break;
 34.1482 +                }
 34.1483 +                break;
 34.1484 +
 34.1485 +            case TYPE_DATE:
 34.1486 +            case TYPE_TIME:
 34.1487 +                int mod = findKeyword(segments[SEG_MODIFIER], DATE_TIME_MODIFIER_KEYWORDS);
 34.1488 +                if (mod >= 0 && mod < DATE_TIME_MODIFIER_KEYWORDS.length) {
 34.1489 +                    if (type == TYPE_DATE) {
 34.1490 +                        newFormat = DateFormat.getDateInstance(DATE_TIME_MODIFIERS[mod],
 34.1491 +                                                               locale);
 34.1492 +                    } else {
 34.1493 +                        newFormat = DateFormat.getTimeInstance(DATE_TIME_MODIFIERS[mod],
 34.1494 +                                                               locale);
 34.1495 +                    }
 34.1496 +                } else {
 34.1497 +                    // SimpleDateFormat pattern
 34.1498 +                    try {
 34.1499 +                        newFormat = new SimpleDateFormat(segments[SEG_MODIFIER], locale);
 34.1500 +                    } catch (IllegalArgumentException e) {
 34.1501 +                        maxOffset = oldMaxOffset;
 34.1502 +                        throw e;
 34.1503 +                    }
 34.1504 +                }
 34.1505 +                break;
 34.1506 +
 34.1507 +            case TYPE_CHOICE:
 34.1508 +                try {
 34.1509 +                    // ChoiceFormat pattern
 34.1510 +                    newFormat = new ChoiceFormat(segments[SEG_MODIFIER]);
 34.1511 +                } catch (Exception e) {
 34.1512 +                    maxOffset = oldMaxOffset;
 34.1513 +                    throw new IllegalArgumentException("Choice Pattern incorrect: "
 34.1514 +                                                       + segments[SEG_MODIFIER], e);
 34.1515 +                }
 34.1516 +                break;
 34.1517 +
 34.1518 +            default:
 34.1519 +                maxOffset = oldMaxOffset;
 34.1520 +                throw new IllegalArgumentException("unknown format type: " +
 34.1521 +                                                   segments[SEG_TYPE]);
 34.1522 +            }
 34.1523 +        }
 34.1524 +        formats[offsetNumber] = newFormat;
 34.1525 +    }
 34.1526 +
 34.1527 +    private static final int findKeyword(String s, String[] list) {
 34.1528 +        for (int i = 0; i < list.length; ++i) {
 34.1529 +            if (s.equals(list[i]))
 34.1530 +                return i;
 34.1531 +        }
 34.1532 +
 34.1533 +        // Try trimmed lowercase.
 34.1534 +        String ls = s.trim().toLowerCase(Locale.ROOT);
 34.1535 +        if (ls != s) {
 34.1536 +            for (int i = 0; i < list.length; ++i) {
 34.1537 +                if (ls.equals(list[i]))
 34.1538 +                    return i;
 34.1539 +            }
 34.1540 +        }
 34.1541 +        return -1;
 34.1542 +    }
 34.1543 +
 34.1544 +    private static final void copyAndFixQuotes(String source, int start, int end,
 34.1545 +                                               StringBuilder target) {
 34.1546 +        boolean quoted = false;
 34.1547 +
 34.1548 +        for (int i = start; i < end; ++i) {
 34.1549 +            char ch = source.charAt(i);
 34.1550 +            if (ch == '{') {
 34.1551 +                if (!quoted) {
 34.1552 +                    target.append('\'');
 34.1553 +                    quoted = true;
 34.1554 +                }
 34.1555 +                target.append(ch);
 34.1556 +            } else if (ch == '\'') {
 34.1557 +                target.append("''");
 34.1558 +            } else {
 34.1559 +                if (quoted) {
 34.1560 +                    target.append('\'');
 34.1561 +                    quoted = false;
 34.1562 +                }
 34.1563 +                target.append(ch);
 34.1564 +            }
 34.1565 +        }
 34.1566 +        if (quoted) {
 34.1567 +            target.append('\'');
 34.1568 +        }
 34.1569 +    }
 34.1570 +
 34.1571 +    /**
 34.1572 +     * After reading an object from the input stream, do a simple verification
 34.1573 +     * to maintain class invariants.
 34.1574 +     * @throws InvalidObjectException if the objects read from the stream is invalid.
 34.1575 +     */
 34.1576 +    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
 34.1577 +        in.defaultReadObject();
 34.1578 +        boolean isValid = maxOffset >= -1
 34.1579 +                && formats.length > maxOffset
 34.1580 +                && offsets.length > maxOffset
 34.1581 +                && argumentNumbers.length > maxOffset;
 34.1582 +        if (isValid) {
 34.1583 +            int lastOffset = pattern.length() + 1;
 34.1584 +            for (int i = maxOffset; i >= 0; --i) {
 34.1585 +                if ((offsets[i] < 0) || (offsets[i] > lastOffset)) {
 34.1586 +                    isValid = false;
 34.1587 +                    break;
 34.1588 +                } else {
 34.1589 +                    lastOffset = offsets[i];
 34.1590 +                }
 34.1591 +            }
 34.1592 +        }
 34.1593 +        if (!isValid) {
 34.1594 +            throw new InvalidObjectException("Could not reconstruct MessageFormat from corrupt stream.");
 34.1595 +        }
 34.1596 +    }
 34.1597 +}
    35.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    35.2 +++ b/rt/emul/compact/src/main/java/java/text/NumberFormat.java	Thu Oct 03 15:40:35 2013 +0200
    35.3 @@ -0,0 +1,1162 @@
    35.4 +/*
    35.5 + * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
    35.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    35.7 + *
    35.8 + * This code is free software; you can redistribute it and/or modify it
    35.9 + * under the terms of the GNU General Public License version 2 only, as
   35.10 + * published by the Free Software Foundation.  Oracle designates this
   35.11 + * particular file as subject to the "Classpath" exception as provided
   35.12 + * by Oracle in the LICENSE file that accompanied this code.
   35.13 + *
   35.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   35.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   35.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   35.17 + * version 2 for more details (a copy is included in the LICENSE file that
   35.18 + * accompanied this code).
   35.19 + *
   35.20 + * You should have received a copy of the GNU General Public License version
   35.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   35.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   35.23 + *
   35.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   35.25 + * or visit www.oracle.com if you need additional information or have any
   35.26 + * questions.
   35.27 + */
   35.28 +
   35.29 +/*
   35.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   35.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   35.32 + *
   35.33 + *   The original version of this source code and documentation is copyrighted
   35.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   35.35 + * materials are provided under terms of a License Agreement between Taligent
   35.36 + * and Sun. This technology is protected by multiple US and International
   35.37 + * patents. This notice and attribution to Taligent may not be removed.
   35.38 + *   Taligent is a registered trademark of Taligent, Inc.
   35.39 + *
   35.40 + */
   35.41 +
   35.42 +package java.text;
   35.43 +
   35.44 +import java.io.InvalidObjectException;
   35.45 +import java.io.IOException;
   35.46 +import java.io.ObjectInputStream;
   35.47 +import java.io.ObjectOutputStream;
   35.48 +import java.math.BigInteger;
   35.49 +import java.math.RoundingMode;
   35.50 +import java.text.spi.NumberFormatProvider;
   35.51 +import java.util.Currency;
   35.52 +import java.util.HashMap;
   35.53 +import java.util.Hashtable;
   35.54 +import java.util.Locale;
   35.55 +import java.util.Map;
   35.56 +import java.util.ResourceBundle;
   35.57 +import java.util.concurrent.atomic.AtomicInteger;
   35.58 +import java.util.concurrent.atomic.AtomicLong;
   35.59 +import java.util.spi.LocaleServiceProvider;
   35.60 +import sun.util.LocaleServiceProviderPool;
   35.61 +import sun.util.resources.LocaleData;
   35.62 +
   35.63 +/**
   35.64 + * <code>NumberFormat</code> is the abstract base class for all number
   35.65 + * formats. This class provides the interface for formatting and parsing
   35.66 + * numbers. <code>NumberFormat</code> also provides methods for determining
   35.67 + * which locales have number formats, and what their names are.
   35.68 + *
   35.69 + * <p>
   35.70 + * <code>NumberFormat</code> helps you to format and parse numbers for any locale.
   35.71 + * Your code can be completely independent of the locale conventions for
   35.72 + * decimal points, thousands-separators, or even the particular decimal
   35.73 + * digits used, or whether the number format is even decimal.
   35.74 + *
   35.75 + * <p>
   35.76 + * To format a number for the current Locale, use one of the factory
   35.77 + * class methods:
   35.78 + * <blockquote>
   35.79 + * <pre>
   35.80 + *  myString = NumberFormat.getInstance().format(myNumber);
   35.81 + * </pre>
   35.82 + * </blockquote>
   35.83 + * If you are formatting multiple numbers, it is
   35.84 + * more efficient to get the format and use it multiple times so that
   35.85 + * the system doesn't have to fetch the information about the local
   35.86 + * language and country conventions multiple times.
   35.87 + * <blockquote>
   35.88 + * <pre>
   35.89 + * NumberFormat nf = NumberFormat.getInstance();
   35.90 + * for (int i = 0; i < myNumber.length; ++i) {
   35.91 + *     output.println(nf.format(myNumber[i]) + "; ");
   35.92 + * }
   35.93 + * </pre>
   35.94 + * </blockquote>
   35.95 + * To format a number for a different Locale, specify it in the
   35.96 + * call to <code>getInstance</code>.
   35.97 + * <blockquote>
   35.98 + * <pre>
   35.99 + * NumberFormat nf = NumberFormat.getInstance(Locale.FRENCH);
  35.100 + * </pre>
  35.101 + * </blockquote>
  35.102 + * You can also use a <code>NumberFormat</code> to parse numbers:
  35.103 + * <blockquote>
  35.104 + * <pre>
  35.105 + * myNumber = nf.parse(myString);
  35.106 + * </pre>
  35.107 + * </blockquote>
  35.108 + * Use <code>getInstance</code> or <code>getNumberInstance</code> to get the
  35.109 + * normal number format. Use <code>getIntegerInstance</code> to get an
  35.110 + * integer number format. Use <code>getCurrencyInstance</code> to get the
  35.111 + * currency number format. And use <code>getPercentInstance</code> to get a
  35.112 + * format for displaying percentages. With this format, a fraction like
  35.113 + * 0.53 is displayed as 53%.
  35.114 + *
  35.115 + * <p>
  35.116 + * You can also control the display of numbers with such methods as
  35.117 + * <code>setMinimumFractionDigits</code>.
  35.118 + * If you want even more control over the format or parsing,
  35.119 + * or want to give your users more control,
  35.120 + * you can try casting the <code>NumberFormat</code> you get from the factory methods
  35.121 + * to a <code>DecimalFormat</code>. This will work for the vast majority
  35.122 + * of locales; just remember to put it in a <code>try</code> block in case you
  35.123 + * encounter an unusual one.
  35.124 + *
  35.125 + * <p>
  35.126 + * NumberFormat and DecimalFormat are designed such that some controls
  35.127 + * work for formatting and others work for parsing.  The following is
  35.128 + * the detailed description for each these control methods,
  35.129 + * <p>
  35.130 + * setParseIntegerOnly : only affects parsing, e.g.
  35.131 + * if true,  "3456.78" -> 3456 (and leaves the parse position just after index 6)
  35.132 + * if false, "3456.78" -> 3456.78 (and leaves the parse position just after index 8)
  35.133 + * This is independent of formatting.  If you want to not show a decimal point
  35.134 + * where there might be no digits after the decimal point, use
  35.135 + * setDecimalSeparatorAlwaysShown.
  35.136 + * <p>
  35.137 + * setDecimalSeparatorAlwaysShown : only affects formatting, and only where
  35.138 + * there might be no digits after the decimal point, such as with a pattern
  35.139 + * like "#,##0.##", e.g.,
  35.140 + * if true,  3456.00 -> "3,456."
  35.141 + * if false, 3456.00 -> "3456"
  35.142 + * This is independent of parsing.  If you want parsing to stop at the decimal
  35.143 + * point, use setParseIntegerOnly.
  35.144 + *
  35.145 + * <p>
  35.146 + * You can also use forms of the <code>parse</code> and <code>format</code>
  35.147 + * methods with <code>ParsePosition</code> and <code>FieldPosition</code> to
  35.148 + * allow you to:
  35.149 + * <ul>
  35.150 + * <li> progressively parse through pieces of a string
  35.151 + * <li> align the decimal point and other areas
  35.152 + * </ul>
  35.153 + * For example, you can align numbers in two ways:
  35.154 + * <ol>
  35.155 + * <li> If you are using a monospaced font with spacing for alignment,
  35.156 + *      you can pass the <code>FieldPosition</code> in your format call, with
  35.157 + *      <code>field</code> = <code>INTEGER_FIELD</code>. On output,
  35.158 + *      <code>getEndIndex</code> will be set to the offset between the
  35.159 + *      last character of the integer and the decimal. Add
  35.160 + *      (desiredSpaceCount - getEndIndex) spaces at the front of the string.
  35.161 + *
  35.162 + * <li> If you are using proportional fonts,
  35.163 + *      instead of padding with spaces, measure the width
  35.164 + *      of the string in pixels from the start to <code>getEndIndex</code>.
  35.165 + *      Then move the pen by
  35.166 + *      (desiredPixelWidth - widthToAlignmentPoint) before drawing the text.
  35.167 + *      It also works where there is no decimal, but possibly additional
  35.168 + *      characters at the end, e.g., with parentheses in negative
  35.169 + *      numbers: "(12)" for -12.
  35.170 + * </ol>
  35.171 + *
  35.172 + * <h4><a name="synchronization">Synchronization</a></h4>
  35.173 + *
  35.174 + * <p>
  35.175 + * Number formats are generally not synchronized.
  35.176 + * It is recommended to create separate format instances for each thread.
  35.177 + * If multiple threads access a format concurrently, it must be synchronized
  35.178 + * externally.
  35.179 + *
  35.180 + * @see          DecimalFormat
  35.181 + * @see          ChoiceFormat
  35.182 + * @author       Mark Davis
  35.183 + * @author       Helena Shih
  35.184 + */
  35.185 +public abstract class NumberFormat extends Format  {
  35.186 +
  35.187 +    /**
  35.188 +     * Field constant used to construct a FieldPosition object. Signifies that
  35.189 +     * the position of the integer part of a formatted number should be returned.
  35.190 +     * @see java.text.FieldPosition
  35.191 +     */
  35.192 +    public static final int INTEGER_FIELD = 0;
  35.193 +
  35.194 +    /**
  35.195 +     * Field constant used to construct a FieldPosition object. Signifies that
  35.196 +     * the position of the fraction part of a formatted number should be returned.
  35.197 +     * @see java.text.FieldPosition
  35.198 +     */
  35.199 +    public static final int FRACTION_FIELD = 1;
  35.200 +
  35.201 +    /**
  35.202 +     * Sole constructor.  (For invocation by subclass constructors, typically
  35.203 +     * implicit.)
  35.204 +     */
  35.205 +    protected NumberFormat() {
  35.206 +    }
  35.207 +
  35.208 +    /**
  35.209 +     * Formats a number and appends the resulting text to the given string
  35.210 +     * buffer.
  35.211 +     * The number can be of any subclass of {@link java.lang.Number}.
  35.212 +     * <p>
  35.213 +     * This implementation extracts the number's value using
  35.214 +     * {@link java.lang.Number#longValue()} for all integral type values that
  35.215 +     * can be converted to <code>long</code> without loss of information,
  35.216 +     * including <code>BigInteger</code> values with a
  35.217 +     * {@link java.math.BigInteger#bitLength() bit length} of less than 64,
  35.218 +     * and {@link java.lang.Number#doubleValue()} for all other types. It
  35.219 +     * then calls
  35.220 +     * {@link #format(long,java.lang.StringBuffer,java.text.FieldPosition)}
  35.221 +     * or {@link #format(double,java.lang.StringBuffer,java.text.FieldPosition)}.
  35.222 +     * This may result in loss of magnitude information and precision for
  35.223 +     * <code>BigInteger</code> and <code>BigDecimal</code> values.
  35.224 +     * @param number     the number to format
  35.225 +     * @param toAppendTo the <code>StringBuffer</code> to which the formatted
  35.226 +     *                   text is to be appended
  35.227 +     * @param pos        On input: an alignment field, if desired.
  35.228 +     *                   On output: the offsets of the alignment field.
  35.229 +     * @return           the value passed in as <code>toAppendTo</code>
  35.230 +     * @exception        IllegalArgumentException if <code>number</code> is
  35.231 +     *                   null or not an instance of <code>Number</code>.
  35.232 +     * @exception        NullPointerException if <code>toAppendTo</code> or
  35.233 +     *                   <code>pos</code> is null
  35.234 +     * @exception        ArithmeticException if rounding is needed with rounding
  35.235 +     *                   mode being set to RoundingMode.UNNECESSARY
  35.236 +     * @see              java.text.FieldPosition
  35.237 +     */
  35.238 +    public StringBuffer format(Object number,
  35.239 +                               StringBuffer toAppendTo,
  35.240 +                               FieldPosition pos) {
  35.241 +        if (number instanceof Long || number instanceof Integer ||
  35.242 +            number instanceof Short || number instanceof Byte ||
  35.243 +            number instanceof AtomicInteger || number instanceof AtomicLong ||
  35.244 +            (number instanceof BigInteger &&
  35.245 +             ((BigInteger)number).bitLength() < 64)) {
  35.246 +            return format(((Number)number).longValue(), toAppendTo, pos);
  35.247 +        } else if (number instanceof Number) {
  35.248 +            return format(((Number)number).doubleValue(), toAppendTo, pos);
  35.249 +        } else {
  35.250 +            throw new IllegalArgumentException("Cannot format given Object as a Number");
  35.251 +        }
  35.252 +    }
  35.253 +
  35.254 +    /**
  35.255 +     * Parses text from a string to produce a <code>Number</code>.
  35.256 +     * <p>
  35.257 +     * The method attempts to parse text starting at the index given by
  35.258 +     * <code>pos</code>.
  35.259 +     * If parsing succeeds, then the index of <code>pos</code> is updated
  35.260 +     * to the index after the last character used (parsing does not necessarily
  35.261 +     * use all characters up to the end of the string), and the parsed
  35.262 +     * number is returned. The updated <code>pos</code> can be used to
  35.263 +     * indicate the starting point for the next call to this method.
  35.264 +     * If an error occurs, then the index of <code>pos</code> is not
  35.265 +     * changed, the error index of <code>pos</code> is set to the index of
  35.266 +     * the character where the error occurred, and null is returned.
  35.267 +     * <p>
  35.268 +     * See the {@link #parse(String, ParsePosition)} method for more information
  35.269 +     * on number parsing.
  35.270 +     *
  35.271 +     * @param source A <code>String</code>, part of which should be parsed.
  35.272 +     * @param pos A <code>ParsePosition</code> object with index and error
  35.273 +     *            index information as described above.
  35.274 +     * @return A <code>Number</code> parsed from the string. In case of
  35.275 +     *         error, returns null.
  35.276 +     * @exception NullPointerException if <code>pos</code> is null.
  35.277 +     */
  35.278 +    public final Object parseObject(String source, ParsePosition pos) {
  35.279 +        return parse(source, pos);
  35.280 +    }
  35.281 +
  35.282 +   /**
  35.283 +     * Specialization of format.
  35.284 +     * @exception        ArithmeticException if rounding is needed with rounding
  35.285 +     *                   mode being set to RoundingMode.UNNECESSARY
  35.286 +     * @see java.text.Format#format
  35.287 +     */
  35.288 +    public final String format(double number) {
  35.289 +        return format(number, new StringBuffer(),
  35.290 +                      DontCareFieldPosition.INSTANCE).toString();
  35.291 +    }
  35.292 +
  35.293 +   /**
  35.294 +     * Specialization of format.
  35.295 +     * @exception        ArithmeticException if rounding is needed with rounding
  35.296 +     *                   mode being set to RoundingMode.UNNECESSARY
  35.297 +     * @see java.text.Format#format
  35.298 +     */
  35.299 +    public final String format(long number) {
  35.300 +        return format(number, new StringBuffer(),
  35.301 +                      DontCareFieldPosition.INSTANCE).toString();
  35.302 +    }
  35.303 +
  35.304 +   /**
  35.305 +     * Specialization of format.
  35.306 +     * @exception        ArithmeticException if rounding is needed with rounding
  35.307 +     *                   mode being set to RoundingMode.UNNECESSARY
  35.308 +     * @see java.text.Format#format
  35.309 +     */
  35.310 +    public abstract StringBuffer format(double number,
  35.311 +                                        StringBuffer toAppendTo,
  35.312 +                                        FieldPosition pos);
  35.313 +
  35.314 +   /**
  35.315 +     * Specialization of format.
  35.316 +     * @exception        ArithmeticException if rounding is needed with rounding
  35.317 +     *                   mode being set to RoundingMode.UNNECESSARY
  35.318 +     * @see java.text.Format#format
  35.319 +     */
  35.320 +    public abstract StringBuffer format(long number,
  35.321 +                                        StringBuffer toAppendTo,
  35.322 +                                        FieldPosition pos);
  35.323 +
  35.324 +   /**
  35.325 +     * Returns a Long if possible (e.g., within the range [Long.MIN_VALUE,
  35.326 +     * Long.MAX_VALUE] and with no decimals), otherwise a Double.
  35.327 +     * If IntegerOnly is set, will stop at a decimal
  35.328 +     * point (or equivalent; e.g., for rational numbers "1 2/3", will stop
  35.329 +     * after the 1).
  35.330 +     * Does not throw an exception; if no object can be parsed, index is
  35.331 +     * unchanged!
  35.332 +     * @see java.text.NumberFormat#isParseIntegerOnly
  35.333 +     * @see java.text.Format#parseObject
  35.334 +     */
  35.335 +    public abstract Number parse(String source, ParsePosition parsePosition);
  35.336 +
  35.337 +    /**
  35.338 +     * Parses text from the beginning of the given string to produce a number.
  35.339 +     * The method may not use the entire text of the given string.
  35.340 +     * <p>
  35.341 +     * See the {@link #parse(String, ParsePosition)} method for more information
  35.342 +     * on number parsing.
  35.343 +     *
  35.344 +     * @param source A <code>String</code> whose beginning should be parsed.
  35.345 +     * @return A <code>Number</code> parsed from the string.
  35.346 +     * @exception ParseException if the beginning of the specified string
  35.347 +     *            cannot be parsed.
  35.348 +     */
  35.349 +    public Number parse(String source) throws ParseException {
  35.350 +        ParsePosition parsePosition = new ParsePosition(0);
  35.351 +        Number result = parse(source, parsePosition);
  35.352 +        if (parsePosition.index == 0) {
  35.353 +            throw new ParseException("Unparseable number: \"" + source + "\"",
  35.354 +                                     parsePosition.errorIndex);
  35.355 +        }
  35.356 +        return result;
  35.357 +    }
  35.358 +
  35.359 +    /**
  35.360 +     * Returns true if this format will parse numbers as integers only.
  35.361 +     * For example in the English locale, with ParseIntegerOnly true, the
  35.362 +     * string "1234." would be parsed as the integer value 1234 and parsing
  35.363 +     * would stop at the "." character.  Of course, the exact format accepted
  35.364 +     * by the parse operation is locale dependant and determined by sub-classes
  35.365 +     * of NumberFormat.
  35.366 +     */
  35.367 +    public boolean isParseIntegerOnly() {
  35.368 +        return parseIntegerOnly;
  35.369 +    }
  35.370 +
  35.371 +    /**
  35.372 +     * Sets whether or not numbers should be parsed as integers only.
  35.373 +     * @see #isParseIntegerOnly
  35.374 +     */
  35.375 +    public void setParseIntegerOnly(boolean value) {
  35.376 +        parseIntegerOnly = value;
  35.377 +    }
  35.378 +
  35.379 +    //============== Locale Stuff =====================
  35.380 +
  35.381 +    /**
  35.382 +     * Returns a general-purpose number format for the current default locale.
  35.383 +     * This is the same as calling
  35.384 +     * {@link #getNumberInstance() getNumberInstance()}.
  35.385 +     */
  35.386 +    public final static NumberFormat getInstance() {
  35.387 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
  35.388 +    }
  35.389 +
  35.390 +    /**
  35.391 +     * Returns a general-purpose number format for the specified locale.
  35.392 +     * This is the same as calling
  35.393 +     * {@link #getNumberInstance(java.util.Locale) getNumberInstance(inLocale)}.
  35.394 +     */
  35.395 +    public static NumberFormat getInstance(Locale inLocale) {
  35.396 +        return getInstance(inLocale, NUMBERSTYLE);
  35.397 +    }
  35.398 +
  35.399 +    /**
  35.400 +     * Returns a general-purpose number format for the current default locale.
  35.401 +     */
  35.402 +    public final static NumberFormat getNumberInstance() {
  35.403 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), NUMBERSTYLE);
  35.404 +    }
  35.405 +
  35.406 +    /**
  35.407 +     * Returns a general-purpose number format for the specified locale.
  35.408 +     */
  35.409 +    public static NumberFormat getNumberInstance(Locale inLocale) {
  35.410 +        return getInstance(inLocale, NUMBERSTYLE);
  35.411 +    }
  35.412 +
  35.413 +    /**
  35.414 +     * Returns an integer number format for the current default locale. The
  35.415 +     * returned number format is configured to round floating point numbers
  35.416 +     * to the nearest integer using half-even rounding (see {@link
  35.417 +     * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
  35.418 +     * and to parse only the integer part of an input string (see {@link
  35.419 +     * #isParseIntegerOnly isParseIntegerOnly}).
  35.420 +     *
  35.421 +     * @see #getRoundingMode()
  35.422 +     * @return a number format for integer values
  35.423 +     * @since 1.4
  35.424 +     */
  35.425 +    public final static NumberFormat getIntegerInstance() {
  35.426 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), INTEGERSTYLE);
  35.427 +    }
  35.428 +
  35.429 +    /**
  35.430 +     * Returns an integer number format for the specified locale. The
  35.431 +     * returned number format is configured to round floating point numbers
  35.432 +     * to the nearest integer using half-even rounding (see {@link
  35.433 +     * java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}) for formatting,
  35.434 +     * and to parse only the integer part of an input string (see {@link
  35.435 +     * #isParseIntegerOnly isParseIntegerOnly}).
  35.436 +     *
  35.437 +     * @see #getRoundingMode()
  35.438 +     * @return a number format for integer values
  35.439 +     * @since 1.4
  35.440 +     */
  35.441 +    public static NumberFormat getIntegerInstance(Locale inLocale) {
  35.442 +        return getInstance(inLocale, INTEGERSTYLE);
  35.443 +    }
  35.444 +
  35.445 +    /**
  35.446 +     * Returns a currency format for the current default locale.
  35.447 +     */
  35.448 +    public final static NumberFormat getCurrencyInstance() {
  35.449 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), CURRENCYSTYLE);
  35.450 +    }
  35.451 +
  35.452 +    /**
  35.453 +     * Returns a currency format for the specified locale.
  35.454 +     */
  35.455 +    public static NumberFormat getCurrencyInstance(Locale inLocale) {
  35.456 +        return getInstance(inLocale, CURRENCYSTYLE);
  35.457 +    }
  35.458 +
  35.459 +    /**
  35.460 +     * Returns a percentage format for the current default locale.
  35.461 +     */
  35.462 +    public final static NumberFormat getPercentInstance() {
  35.463 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), PERCENTSTYLE);
  35.464 +    }
  35.465 +
  35.466 +    /**
  35.467 +     * Returns a percentage format for the specified locale.
  35.468 +     */
  35.469 +    public static NumberFormat getPercentInstance(Locale inLocale) {
  35.470 +        return getInstance(inLocale, PERCENTSTYLE);
  35.471 +    }
  35.472 +
  35.473 +    /**
  35.474 +     * Returns a scientific format for the current default locale.
  35.475 +     */
  35.476 +    /*public*/ final static NumberFormat getScientificInstance() {
  35.477 +        return getInstance(Locale.getDefault(Locale.Category.FORMAT), SCIENTIFICSTYLE);
  35.478 +    }
  35.479 +
  35.480 +    /**
  35.481 +     * Returns a scientific format for the specified locale.
  35.482 +     */
  35.483 +    /*public*/ static NumberFormat getScientificInstance(Locale inLocale) {
  35.484 +        return getInstance(inLocale, SCIENTIFICSTYLE);
  35.485 +    }
  35.486 +
  35.487 +    /**
  35.488 +     * Returns an array of all locales for which the
  35.489 +     * <code>get*Instance</code> methods of this class can return
  35.490 +     * localized instances.
  35.491 +     * The returned array represents the union of locales supported by the Java
  35.492 +     * runtime and by installed
  35.493 +     * {@link java.text.spi.NumberFormatProvider NumberFormatProvider} implementations.
  35.494 +     * It must contain at least a <code>Locale</code> instance equal to
  35.495 +     * {@link java.util.Locale#US Locale.US}.
  35.496 +     *
  35.497 +     * @return An array of locales for which localized
  35.498 +     *         <code>NumberFormat</code> instances are available.
  35.499 +     */
  35.500 +    public static Locale[] getAvailableLocales() {
  35.501 +        LocaleServiceProviderPool pool =
  35.502 +            LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
  35.503 +        return pool.getAvailableLocales();
  35.504 +    }
  35.505 +
  35.506 +    /**
  35.507 +     * Overrides hashCode
  35.508 +     */
  35.509 +    public int hashCode() {
  35.510 +        return maximumIntegerDigits * 37 + maxFractionDigits;
  35.511 +        // just enough fields for a reasonable distribution
  35.512 +    }
  35.513 +
  35.514 +    /**
  35.515 +     * Overrides equals
  35.516 +     */
  35.517 +    public boolean equals(Object obj) {
  35.518 +        if (obj == null) {
  35.519 +            return false;
  35.520 +        }
  35.521 +        if (this == obj) {
  35.522 +            return true;
  35.523 +        }
  35.524 +        if (getClass() != obj.getClass()) {
  35.525 +            return false;
  35.526 +        }
  35.527 +        NumberFormat other = (NumberFormat) obj;
  35.528 +        return (maximumIntegerDigits == other.maximumIntegerDigits
  35.529 +            && minimumIntegerDigits == other.minimumIntegerDigits
  35.530 +            && maximumFractionDigits == other.maximumFractionDigits
  35.531 +            && minimumFractionDigits == other.minimumFractionDigits
  35.532 +            && groupingUsed == other.groupingUsed
  35.533 +            && parseIntegerOnly == other.parseIntegerOnly);
  35.534 +    }
  35.535 +
  35.536 +    /**
  35.537 +     * Overrides Cloneable
  35.538 +     */
  35.539 +    public Object clone() {
  35.540 +        NumberFormat other = (NumberFormat) super.clone();
  35.541 +        return other;
  35.542 +    }
  35.543 +
  35.544 +    /**
  35.545 +     * Returns true if grouping is used in this format. For example, in the
  35.546 +     * English locale, with grouping on, the number 1234567 might be formatted
  35.547 +     * as "1,234,567". The grouping separator as well as the size of each group
  35.548 +     * is locale dependant and is determined by sub-classes of NumberFormat.
  35.549 +     * @see #setGroupingUsed
  35.550 +     */
  35.551 +    public boolean isGroupingUsed() {
  35.552 +        return groupingUsed;
  35.553 +    }
  35.554 +
  35.555 +    /**
  35.556 +     * Set whether or not grouping will be used in this format.
  35.557 +     * @see #isGroupingUsed
  35.558 +     */
  35.559 +    public void setGroupingUsed(boolean newValue) {
  35.560 +        groupingUsed = newValue;
  35.561 +    }
  35.562 +
  35.563 +    /**
  35.564 +     * Returns the maximum number of digits allowed in the integer portion of a
  35.565 +     * number.
  35.566 +     * @see #setMaximumIntegerDigits
  35.567 +     */
  35.568 +    public int getMaximumIntegerDigits() {
  35.569 +        return maximumIntegerDigits;
  35.570 +    }
  35.571 +
  35.572 +    /**
  35.573 +     * Sets the maximum number of digits allowed in the integer portion of a
  35.574 +     * number. maximumIntegerDigits must be >= minimumIntegerDigits.  If the
  35.575 +     * new value for maximumIntegerDigits is less than the current value
  35.576 +     * of minimumIntegerDigits, then minimumIntegerDigits will also be set to
  35.577 +     * the new value.
  35.578 +     * @param newValue the maximum number of integer digits to be shown; if
  35.579 +     * less than zero, then zero is used. The concrete subclass may enforce an
  35.580 +     * upper limit to this value appropriate to the numeric type being formatted.
  35.581 +     * @see #getMaximumIntegerDigits
  35.582 +     */
  35.583 +    public void setMaximumIntegerDigits(int newValue) {
  35.584 +        maximumIntegerDigits = Math.max(0,newValue);
  35.585 +        if (minimumIntegerDigits > maximumIntegerDigits) {
  35.586 +            minimumIntegerDigits = maximumIntegerDigits;
  35.587 +        }
  35.588 +    }
  35.589 +
  35.590 +    /**
  35.591 +     * Returns the minimum number of digits allowed in the integer portion of a
  35.592 +     * number.
  35.593 +     * @see #setMinimumIntegerDigits
  35.594 +     */
  35.595 +    public int getMinimumIntegerDigits() {
  35.596 +        return minimumIntegerDigits;
  35.597 +    }
  35.598 +
  35.599 +    /**
  35.600 +     * Sets the minimum number of digits allowed in the integer portion of a
  35.601 +     * number. minimumIntegerDigits must be <= maximumIntegerDigits.  If the
  35.602 +     * new value for minimumIntegerDigits exceeds the current value
  35.603 +     * of maximumIntegerDigits, then maximumIntegerDigits will also be set to
  35.604 +     * the new value
  35.605 +     * @param newValue the minimum number of integer digits to be shown; if
  35.606 +     * less than zero, then zero is used. The concrete subclass may enforce an
  35.607 +     * upper limit to this value appropriate to the numeric type being formatted.
  35.608 +     * @see #getMinimumIntegerDigits
  35.609 +     */
  35.610 +    public void setMinimumIntegerDigits(int newValue) {
  35.611 +        minimumIntegerDigits = Math.max(0,newValue);
  35.612 +        if (minimumIntegerDigits > maximumIntegerDigits) {
  35.613 +            maximumIntegerDigits = minimumIntegerDigits;
  35.614 +        }
  35.615 +    }
  35.616 +
  35.617 +    /**
  35.618 +     * Returns the maximum number of digits allowed in the fraction portion of a
  35.619 +     * number.
  35.620 +     * @see #setMaximumFractionDigits
  35.621 +     */
  35.622 +    public int getMaximumFractionDigits() {
  35.623 +        return maximumFractionDigits;
  35.624 +    }
  35.625 +
  35.626 +    /**
  35.627 +     * Sets the maximum number of digits allowed in the fraction portion of a
  35.628 +     * number. maximumFractionDigits must be >= minimumFractionDigits.  If the
  35.629 +     * new value for maximumFractionDigits is less than the current value
  35.630 +     * of minimumFractionDigits, then minimumFractionDigits will also be set to
  35.631 +     * the new value.
  35.632 +     * @param newValue the maximum number of fraction digits to be shown; if
  35.633 +     * less than zero, then zero is used. The concrete subclass may enforce an
  35.634 +     * upper limit to this value appropriate to the numeric type being formatted.
  35.635 +     * @see #getMaximumFractionDigits
  35.636 +     */
  35.637 +    public void setMaximumFractionDigits(int newValue) {
  35.638 +        maximumFractionDigits = Math.max(0,newValue);
  35.639 +        if (maximumFractionDigits < minimumFractionDigits) {
  35.640 +            minimumFractionDigits = maximumFractionDigits;
  35.641 +        }
  35.642 +    }
  35.643 +
  35.644 +    /**
  35.645 +     * Returns the minimum number of digits allowed in the fraction portion of a
  35.646 +     * number.
  35.647 +     * @see #setMinimumFractionDigits
  35.648 +     */
  35.649 +    public int getMinimumFractionDigits() {
  35.650 +        return minimumFractionDigits;
  35.651 +    }
  35.652 +
  35.653 +    /**
  35.654 +     * Sets the minimum number of digits allowed in the fraction portion of a
  35.655 +     * number. minimumFractionDigits must be <= maximumFractionDigits.  If the
  35.656 +     * new value for minimumFractionDigits exceeds the current value
  35.657 +     * of maximumFractionDigits, then maximumIntegerDigits will also be set to
  35.658 +     * the new value
  35.659 +     * @param newValue the minimum number of fraction digits to be shown; if
  35.660 +     * less than zero, then zero is used. The concrete subclass may enforce an
  35.661 +     * upper limit to this value appropriate to the numeric type being formatted.
  35.662 +     * @see #getMinimumFractionDigits
  35.663 +     */
  35.664 +    public void setMinimumFractionDigits(int newValue) {
  35.665 +        minimumFractionDigits = Math.max(0,newValue);
  35.666 +        if (maximumFractionDigits < minimumFractionDigits) {
  35.667 +            maximumFractionDigits = minimumFractionDigits;
  35.668 +        }
  35.669 +    }
  35.670 +
  35.671 +    /**
  35.672 +     * Gets the currency used by this number format when formatting
  35.673 +     * currency values. The initial value is derived in a locale dependent
  35.674 +     * way. The returned value may be null if no valid
  35.675 +     * currency could be determined and no currency has been set using
  35.676 +     * {@link #setCurrency(java.util.Currency) setCurrency}.
  35.677 +     * <p>
  35.678 +     * The default implementation throws
  35.679 +     * <code>UnsupportedOperationException</code>.
  35.680 +     *
  35.681 +     * @return the currency used by this number format, or <code>null</code>
  35.682 +     * @exception UnsupportedOperationException if the number format class
  35.683 +     * doesn't implement currency formatting
  35.684 +     * @since 1.4
  35.685 +     */
  35.686 +    public Currency getCurrency() {
  35.687 +        throw new UnsupportedOperationException();
  35.688 +    }
  35.689 +
  35.690 +    /**
  35.691 +     * Sets the currency used by this number format when formatting
  35.692 +     * currency values. This does not update the minimum or maximum
  35.693 +     * number of fraction digits used by the number format.
  35.694 +     * <p>
  35.695 +     * The default implementation throws
  35.696 +     * <code>UnsupportedOperationException</code>.
  35.697 +     *
  35.698 +     * @param currency the new currency to be used by this number format
  35.699 +     * @exception UnsupportedOperationException if the number format class
  35.700 +     * doesn't implement currency formatting
  35.701 +     * @exception NullPointerException if <code>currency</code> is null
  35.702 +     * @since 1.4
  35.703 +     */
  35.704 +    public void setCurrency(Currency currency) {
  35.705 +        throw new UnsupportedOperationException();
  35.706 +    }
  35.707 +
  35.708 +    /**
  35.709 +     * Gets the {@link java.math.RoundingMode} used in this NumberFormat.
  35.710 +     * The default implementation of this method in NumberFormat
  35.711 +     * always throws {@link java.lang.UnsupportedOperationException}.
  35.712 +     * Subclasses which handle different rounding modes should override
  35.713 +     * this method.
  35.714 +     *
  35.715 +     * @exception UnsupportedOperationException The default implementation
  35.716 +     *     always throws this exception
  35.717 +     * @return The <code>RoundingMode</code> used for this NumberFormat.
  35.718 +     * @see #setRoundingMode(RoundingMode)
  35.719 +     * @since 1.6
  35.720 +     */
  35.721 +    public RoundingMode getRoundingMode() {
  35.722 +        throw new UnsupportedOperationException();
  35.723 +    }
  35.724 +
  35.725 +    /**
  35.726 +     * Sets the {@link java.math.RoundingMode} used in this NumberFormat.
  35.727 +     * The default implementation of this method in NumberFormat always
  35.728 +     * throws {@link java.lang.UnsupportedOperationException}.
  35.729 +     * Subclasses which handle different rounding modes should override
  35.730 +     * this method.
  35.731 +     *
  35.732 +     * @exception UnsupportedOperationException The default implementation
  35.733 +     *     always throws this exception
  35.734 +     * @exception NullPointerException if <code>roundingMode</code> is null
  35.735 +     * @param roundingMode The <code>RoundingMode</code> to be used
  35.736 +     * @see #getRoundingMode()
  35.737 +     * @since 1.6
  35.738 +     */
  35.739 +    public void setRoundingMode(RoundingMode roundingMode) {
  35.740 +        throw new UnsupportedOperationException();
  35.741 +    }
  35.742 +
  35.743 +    // =======================privates===============================
  35.744 +
  35.745 +    private static NumberFormat getInstance(Locale desiredLocale,
  35.746 +                                           int choice) {
  35.747 +        // Check whether a provider can provide an implementation that's closer
  35.748 +        // to the requested locale than what the Java runtime itself can provide.
  35.749 +        LocaleServiceProviderPool pool =
  35.750 +            LocaleServiceProviderPool.getPool(NumberFormatProvider.class);
  35.751 +        if (pool.hasProviders()) {
  35.752 +            NumberFormat providersInstance = pool.getLocalizedObject(
  35.753 +                                    NumberFormatGetter.INSTANCE,
  35.754 +                                    desiredLocale,
  35.755 +                                    choice);
  35.756 +            if (providersInstance != null) {
  35.757 +                return providersInstance;
  35.758 +            }
  35.759 +        }
  35.760 +
  35.761 +        /* try the cache first */
  35.762 +        String[] numberPatterns = (String[])cachedLocaleData.get(desiredLocale);
  35.763 +        if (numberPatterns == null) { /* cache miss */
  35.764 +            ResourceBundle resource = LocaleData.getNumberFormatData(desiredLocale);
  35.765 +            numberPatterns = resource.getStringArray("NumberPatterns");
  35.766 +            /* update cache */
  35.767 +            cachedLocaleData.put(desiredLocale, numberPatterns);
  35.768 +        }
  35.769 +
  35.770 +        DecimalFormatSymbols symbols = DecimalFormatSymbols.getInstance(desiredLocale);
  35.771 +        int entry = (choice == INTEGERSTYLE) ? NUMBERSTYLE : choice;
  35.772 +        DecimalFormat format = new DecimalFormat(numberPatterns[entry], symbols);
  35.773 +
  35.774 +        if (choice == INTEGERSTYLE) {
  35.775 +            format.setMaximumFractionDigits(0);
  35.776 +            format.setDecimalSeparatorAlwaysShown(false);
  35.777 +            format.setParseIntegerOnly(true);
  35.778 +        } else if (choice == CURRENCYSTYLE) {
  35.779 +            format.adjustForCurrencyDefaultFractionDigits();
  35.780 +        }
  35.781 +
  35.782 +        return format;
  35.783 +    }
  35.784 +
  35.785 +    /**
  35.786 +     * First, read in the default serializable data.
  35.787 +     *
  35.788 +     * Then, if <code>serialVersionOnStream</code> is less than 1, indicating that
  35.789 +     * the stream was written by JDK 1.1,
  35.790 +     * set the <code>int</code> fields such as <code>maximumIntegerDigits</code>
  35.791 +     * to be equal to the <code>byte</code> fields such as <code>maxIntegerDigits</code>,
  35.792 +     * since the <code>int</code> fields were not present in JDK 1.1.
  35.793 +     * Finally, set serialVersionOnStream back to the maximum allowed value so that
  35.794 +     * default serialization will work properly if this object is streamed out again.
  35.795 +     *
  35.796 +     * <p>If <code>minimumIntegerDigits</code> is greater than
  35.797 +     * <code>maximumIntegerDigits</code> or <code>minimumFractionDigits</code>
  35.798 +     * is greater than <code>maximumFractionDigits</code>, then the stream data
  35.799 +     * is invalid and this method throws an <code>InvalidObjectException</code>.
  35.800 +     * In addition, if any of these values is negative, then this method throws
  35.801 +     * an <code>InvalidObjectException</code>.
  35.802 +     *
  35.803 +     * @since 1.2
  35.804 +     */
  35.805 +    private void readObject(ObjectInputStream stream)
  35.806 +         throws IOException, ClassNotFoundException
  35.807 +    {
  35.808 +        stream.defaultReadObject();
  35.809 +        if (serialVersionOnStream < 1) {
  35.810 +            // Didn't have additional int fields, reassign to use them.
  35.811 +            maximumIntegerDigits = maxIntegerDigits;
  35.812 +            minimumIntegerDigits = minIntegerDigits;
  35.813 +            maximumFractionDigits = maxFractionDigits;
  35.814 +            minimumFractionDigits = minFractionDigits;
  35.815 +        }
  35.816 +        if (minimumIntegerDigits > maximumIntegerDigits ||
  35.817 +            minimumFractionDigits > maximumFractionDigits ||
  35.818 +            minimumIntegerDigits < 0 || minimumFractionDigits < 0) {
  35.819 +            throw new InvalidObjectException("Digit count range invalid");
  35.820 +        }
  35.821 +        serialVersionOnStream = currentSerialVersion;
  35.822 +    }
  35.823 +
  35.824 +    /**
  35.825 +     * Write out the default serializable data, after first setting
  35.826 +     * the <code>byte</code> fields such as <code>maxIntegerDigits</code> to be
  35.827 +     * equal to the <code>int</code> fields such as <code>maximumIntegerDigits</code>
  35.828 +     * (or to <code>Byte.MAX_VALUE</code>, whichever is smaller), for compatibility
  35.829 +     * with the JDK 1.1 version of the stream format.
  35.830 +     *
  35.831 +     * @since 1.2
  35.832 +     */
  35.833 +    private void writeObject(ObjectOutputStream stream)
  35.834 +         throws IOException
  35.835 +    {
  35.836 +        maxIntegerDigits = (maximumIntegerDigits > Byte.MAX_VALUE) ?
  35.837 +                           Byte.MAX_VALUE : (byte)maximumIntegerDigits;
  35.838 +        minIntegerDigits = (minimumIntegerDigits > Byte.MAX_VALUE) ?
  35.839 +                           Byte.MAX_VALUE : (byte)minimumIntegerDigits;
  35.840 +        maxFractionDigits = (maximumFractionDigits > Byte.MAX_VALUE) ?
  35.841 +                            Byte.MAX_VALUE : (byte)maximumFractionDigits;
  35.842 +        minFractionDigits = (minimumFractionDigits > Byte.MAX_VALUE) ?
  35.843 +                            Byte.MAX_VALUE : (byte)minimumFractionDigits;
  35.844 +        stream.defaultWriteObject();
  35.845 +    }
  35.846 +
  35.847 +    /**
  35.848 +     * Cache to hold the NumberPatterns of a Locale.
  35.849 +     */
  35.850 +    private static final Hashtable cachedLocaleData = new Hashtable(3);
  35.851 +
  35.852 +    // Constants used by factory methods to specify a style of format.
  35.853 +    private static final int NUMBERSTYLE = 0;
  35.854 +    private static final int CURRENCYSTYLE = 1;
  35.855 +    private static final int PERCENTSTYLE = 2;
  35.856 +    private static final int SCIENTIFICSTYLE = 3;
  35.857 +    private static final int INTEGERSTYLE = 4;
  35.858 +
  35.859 +    /**
  35.860 +     * True if the grouping (i.e. thousands) separator is used when
  35.861 +     * formatting and parsing numbers.
  35.862 +     *
  35.863 +     * @serial
  35.864 +     * @see #isGroupingUsed
  35.865 +     */
  35.866 +    private boolean groupingUsed = true;
  35.867 +
  35.868 +    /**
  35.869 +     * The maximum number of digits allowed in the integer portion of a
  35.870 +     * number.  <code>maxIntegerDigits</code> must be greater than or equal to
  35.871 +     * <code>minIntegerDigits</code>.
  35.872 +     * <p>
  35.873 +     * <strong>Note:</strong> This field exists only for serialization
  35.874 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
  35.875 +     * <code>int</code> field <code>maximumIntegerDigits</code> is used instead.
  35.876 +     * When writing to a stream, <code>maxIntegerDigits</code> is set to
  35.877 +     * <code>maximumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
  35.878 +     * whichever is smaller.  When reading from a stream, this field is used
  35.879 +     * only if <code>serialVersionOnStream</code> is less than 1.
  35.880 +     *
  35.881 +     * @serial
  35.882 +     * @see #getMaximumIntegerDigits
  35.883 +     */
  35.884 +    private byte    maxIntegerDigits = 40;
  35.885 +
  35.886 +    /**
  35.887 +     * The minimum number of digits allowed in the integer portion of a
  35.888 +     * number.  <code>minimumIntegerDigits</code> must be less than or equal to
  35.889 +     * <code>maximumIntegerDigits</code>.
  35.890 +     * <p>
  35.891 +     * <strong>Note:</strong> This field exists only for serialization
  35.892 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
  35.893 +     * <code>int</code> field <code>minimumIntegerDigits</code> is used instead.
  35.894 +     * When writing to a stream, <code>minIntegerDigits</code> is set to
  35.895 +     * <code>minimumIntegerDigits</code> or <code>Byte.MAX_VALUE</code>,
  35.896 +     * whichever is smaller.  When reading from a stream, this field is used
  35.897 +     * only if <code>serialVersionOnStream</code> is less than 1.
  35.898 +     *
  35.899 +     * @serial
  35.900 +     * @see #getMinimumIntegerDigits
  35.901 +     */
  35.902 +    private byte    minIntegerDigits = 1;
  35.903 +
  35.904 +    /**
  35.905 +     * The maximum number of digits allowed in the fractional portion of a
  35.906 +     * number.  <code>maximumFractionDigits</code> must be greater than or equal to
  35.907 +     * <code>minimumFractionDigits</code>.
  35.908 +     * <p>
  35.909 +     * <strong>Note:</strong> This field exists only for serialization
  35.910 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
  35.911 +     * <code>int</code> field <code>maximumFractionDigits</code> is used instead.
  35.912 +     * When writing to a stream, <code>maxFractionDigits</code> is set to
  35.913 +     * <code>maximumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
  35.914 +     * whichever is smaller.  When reading from a stream, this field is used
  35.915 +     * only if <code>serialVersionOnStream</code> is less than 1.
  35.916 +     *
  35.917 +     * @serial
  35.918 +     * @see #getMaximumFractionDigits
  35.919 +     */
  35.920 +    private byte    maxFractionDigits = 3;    // invariant, >= minFractionDigits
  35.921 +
  35.922 +    /**
  35.923 +     * The minimum number of digits allowed in the fractional portion of a
  35.924 +     * number.  <code>minimumFractionDigits</code> must be less than or equal to
  35.925 +     * <code>maximumFractionDigits</code>.
  35.926 +     * <p>
  35.927 +     * <strong>Note:</strong> This field exists only for serialization
  35.928 +     * compatibility with JDK 1.1.  In Java platform 2 v1.2 and higher, the new
  35.929 +     * <code>int</code> field <code>minimumFractionDigits</code> is used instead.
  35.930 +     * When writing to a stream, <code>minFractionDigits</code> is set to
  35.931 +     * <code>minimumFractionDigits</code> or <code>Byte.MAX_VALUE</code>,
  35.932 +     * whichever is smaller.  When reading from a stream, this field is used
  35.933 +     * only if <code>serialVersionOnStream</code> is less than 1.
  35.934 +     *
  35.935 +     * @serial
  35.936 +     * @see #getMinimumFractionDigits
  35.937 +     */
  35.938 +    private byte    minFractionDigits = 0;
  35.939 +
  35.940 +    /**
  35.941 +     * True if this format will parse numbers as integers only.
  35.942 +     *
  35.943 +     * @serial
  35.944 +     * @see #isParseIntegerOnly
  35.945 +     */
  35.946 +    private boolean parseIntegerOnly = false;
  35.947 +
  35.948 +    // new fields for 1.2.  byte is too small for integer digits.
  35.949 +
  35.950 +    /**
  35.951 +     * The maximum number of digits allowed in the integer portion of a
  35.952 +     * number.  <code>maximumIntegerDigits</code> must be greater than or equal to
  35.953 +     * <code>minimumIntegerDigits</code>.
  35.954 +     *
  35.955 +     * @serial
  35.956 +     * @since 1.2
  35.957 +     * @see #getMaximumIntegerDigits
  35.958 +     */
  35.959 +    private int    maximumIntegerDigits = 40;
  35.960 +
  35.961 +    /**
  35.962 +     * The minimum number of digits allowed in the integer portion of a
  35.963 +     * number.  <code>minimumIntegerDigits</code> must be less than or equal to
  35.964 +     * <code>maximumIntegerDigits</code>.
  35.965 +     *
  35.966 +     * @serial
  35.967 +     * @since 1.2
  35.968 +     * @see #getMinimumIntegerDigits
  35.969 +     */
  35.970 +    private int    minimumIntegerDigits = 1;
  35.971 +
  35.972 +    /**
  35.973 +     * The maximum number of digits allowed in the fractional portion of a
  35.974 +     * number.  <code>maximumFractionDigits</code> must be greater than or equal to
  35.975 +     * <code>minimumFractionDigits</code>.
  35.976 +     *
  35.977 +     * @serial
  35.978 +     * @since 1.2
  35.979 +     * @see #getMaximumFractionDigits
  35.980 +     */
  35.981 +    private int    maximumFractionDigits = 3;    // invariant, >= minFractionDigits
  35.982 +
  35.983 +    /**
  35.984 +     * The minimum number of digits allowed in the fractional portion of a
  35.985 +     * number.  <code>minimumFractionDigits</code> must be less than or equal to
  35.986 +     * <code>maximumFractionDigits</code>.
  35.987 +     *
  35.988 +     * @serial
  35.989 +     * @since 1.2
  35.990 +     * @see #getMinimumFractionDigits
  35.991 +     */
  35.992 +    private int    minimumFractionDigits = 0;
  35.993 +
  35.994 +    static final int currentSerialVersion = 1;
  35.995 +
  35.996 +    /**
  35.997 +     * Describes the version of <code>NumberFormat</code> present on the stream.
  35.998 +     * Possible values are:
  35.999 +     * <ul>
 35.1000 +     * <li><b>0</b> (or uninitialized): the JDK 1.1 version of the stream format.
 35.1001 +     *     In this version, the <code>int</code> fields such as
 35.1002 +     *     <code>maximumIntegerDigits</code> were not present, and the <code>byte</code>
 35.1003 +     *     fields such as <code>maxIntegerDigits</code> are used instead.
 35.1004 +     *
 35.1005 +     * <li><b>1</b>: the 1.2 version of the stream format.  The values of the
 35.1006 +     *     <code>byte</code> fields such as <code>maxIntegerDigits</code> are ignored,
 35.1007 +     *     and the <code>int</code> fields such as <code>maximumIntegerDigits</code>
 35.1008 +     *     are used instead.
 35.1009 +     * </ul>
 35.1010 +     * When streaming out a <code>NumberFormat</code>, the most recent format
 35.1011 +     * (corresponding to the highest allowable <code>serialVersionOnStream</code>)
 35.1012 +     * is always written.
 35.1013 +     *
 35.1014 +     * @serial
 35.1015 +     * @since 1.2
 35.1016 +     */
 35.1017 +    private int serialVersionOnStream = currentSerialVersion;
 35.1018 +
 35.1019 +    // Removed "implements Cloneable" clause.  Needs to update serialization
 35.1020 +    // ID for backward compatibility.
 35.1021 +    static final long serialVersionUID = -2308460125733713944L;
 35.1022 +
 35.1023 +
 35.1024 +    //
 35.1025 +    // class for AttributedCharacterIterator attributes
 35.1026 +    //
 35.1027 +    /**
 35.1028 +     * Defines constants that are used as attribute keys in the
 35.1029 +     * <code>AttributedCharacterIterator</code> returned
 35.1030 +     * from <code>NumberFormat.formatToCharacterIterator</code> and as
 35.1031 +     * field identifiers in <code>FieldPosition</code>.
 35.1032 +     *
 35.1033 +     * @since 1.4
 35.1034 +     */
 35.1035 +    public static class Field extends Format.Field {
 35.1036 +
 35.1037 +        // Proclaim serial compatibility with 1.4 FCS
 35.1038 +        private static final long serialVersionUID = 7494728892700160890L;
 35.1039 +
 35.1040 +        // table of all instances in this class, used by readResolve
 35.1041 +        private static final Map instanceMap = new HashMap(11);
 35.1042 +
 35.1043 +        /**
 35.1044 +         * Creates a Field instance with the specified
 35.1045 +         * name.
 35.1046 +         *
 35.1047 +         * @param name Name of the attribute
 35.1048 +         */
 35.1049 +        protected Field(String name) {
 35.1050 +            super(name);
 35.1051 +            if (this.getClass() == NumberFormat.Field.class) {
 35.1052 +                instanceMap.put(name, this);
 35.1053 +            }
 35.1054 +        }
 35.1055 +
 35.1056 +        /**
 35.1057 +         * Resolves instances being deserialized to the predefined constants.
 35.1058 +         *
 35.1059 +         * @throws InvalidObjectException if the constant could not be resolved.
 35.1060 +         * @return resolved NumberFormat.Field constant
 35.1061 +         */
 35.1062 +        protected Object readResolve() throws InvalidObjectException {
 35.1063 +            if (this.getClass() != NumberFormat.Field.class) {
 35.1064 +                throw new InvalidObjectException("subclass didn't correctly implement readResolve");
 35.1065 +            }
 35.1066 +
 35.1067 +            Object instance = instanceMap.get(getName());
 35.1068 +            if (instance != null) {
 35.1069 +                return instance;
 35.1070 +            } else {
 35.1071 +                throw new InvalidObjectException("unknown attribute name");
 35.1072 +            }
 35.1073 +        }
 35.1074 +
 35.1075 +        /**
 35.1076 +         * Constant identifying the integer field.
 35.1077 +         */
 35.1078 +        public static final Field INTEGER = new Field("integer");
 35.1079 +
 35.1080 +        /**
 35.1081 +         * Constant identifying the fraction field.
 35.1082 +         */
 35.1083 +        public static final Field FRACTION = new Field("fraction");
 35.1084 +
 35.1085 +        /**
 35.1086 +         * Constant identifying the exponent field.
 35.1087 +         */
 35.1088 +        public static final Field EXPONENT = new Field("exponent");
 35.1089 +
 35.1090 +        /**
 35.1091 +         * Constant identifying the decimal separator field.
 35.1092 +         */
 35.1093 +        public static final Field DECIMAL_SEPARATOR =
 35.1094 +                            new Field("decimal separator");
 35.1095 +
 35.1096 +        /**
 35.1097 +         * Constant identifying the sign field.
 35.1098 +         */
 35.1099 +        public static final Field SIGN = new Field("sign");
 35.1100 +
 35.1101 +        /**
 35.1102 +         * Constant identifying the grouping separator field.
 35.1103 +         */
 35.1104 +        public static final Field GROUPING_SEPARATOR =
 35.1105 +                            new Field("grouping separator");
 35.1106 +
 35.1107 +        /**
 35.1108 +         * Constant identifying the exponent symbol field.
 35.1109 +         */
 35.1110 +        public static final Field EXPONENT_SYMBOL = new
 35.1111 +                            Field("exponent symbol");
 35.1112 +
 35.1113 +        /**
 35.1114 +         * Constant identifying the percent field.
 35.1115 +         */
 35.1116 +        public static final Field PERCENT = new Field("percent");
 35.1117 +
 35.1118 +        /**
 35.1119 +         * Constant identifying the permille field.
 35.1120 +         */
 35.1121 +        public static final Field PERMILLE = new Field("per mille");
 35.1122 +
 35.1123 +        /**
 35.1124 +         * Constant identifying the currency field.
 35.1125 +         */
 35.1126 +        public static final Field CURRENCY = new Field("currency");
 35.1127 +
 35.1128 +        /**
 35.1129 +         * Constant identifying the exponent sign field.
 35.1130 +         */
 35.1131 +        public static final Field EXPONENT_SIGN = new Field("exponent sign");
 35.1132 +    }
 35.1133 +
 35.1134 +    /**
 35.1135 +     * Obtains a NumberFormat instance from a NumberFormatProvider implementation.
 35.1136 +     */
 35.1137 +    private static class NumberFormatGetter
 35.1138 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<NumberFormatProvider,
 35.1139 +                                                                   NumberFormat> {
 35.1140 +        private static final NumberFormatGetter INSTANCE = new NumberFormatGetter();
 35.1141 +
 35.1142 +        public NumberFormat getObject(NumberFormatProvider numberFormatProvider,
 35.1143 +                                Locale locale,
 35.1144 +                                String key,
 35.1145 +                                Object... params) {
 35.1146 +            assert params.length == 1;
 35.1147 +            int choice = (Integer)params[0];
 35.1148 +
 35.1149 +            switch (choice) {
 35.1150 +            case NUMBERSTYLE:
 35.1151 +                return numberFormatProvider.getNumberInstance(locale);
 35.1152 +            case PERCENTSTYLE:
 35.1153 +                return numberFormatProvider.getPercentInstance(locale);
 35.1154 +            case CURRENCYSTYLE:
 35.1155 +                return numberFormatProvider.getCurrencyInstance(locale);
 35.1156 +            case INTEGERSTYLE:
 35.1157 +                return numberFormatProvider.getIntegerInstance(locale);
 35.1158 +            default:
 35.1159 +                assert false : choice;
 35.1160 +            }
 35.1161 +
 35.1162 +            return null;
 35.1163 +        }
 35.1164 +    }
 35.1165 +}
    36.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    36.2 +++ b/rt/emul/compact/src/main/java/java/text/ParseException.java	Thu Oct 03 15:40:35 2013 +0200
    36.3 @@ -0,0 +1,78 @@
    36.4 +/*
    36.5 + * Copyright (c) 1996, 1998, Oracle and/or its affiliates. All rights reserved.
    36.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    36.7 + *
    36.8 + * This code is free software; you can redistribute it and/or modify it
    36.9 + * under the terms of the GNU General Public License version 2 only, as
   36.10 + * published by the Free Software Foundation.  Oracle designates this
   36.11 + * particular file as subject to the "Classpath" exception as provided
   36.12 + * by Oracle in the LICENSE file that accompanied this code.
   36.13 + *
   36.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   36.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   36.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   36.17 + * version 2 for more details (a copy is included in the LICENSE file that
   36.18 + * accompanied this code).
   36.19 + *
   36.20 + * You should have received a copy of the GNU General Public License version
   36.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   36.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   36.23 + *
   36.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   36.25 + * or visit www.oracle.com if you need additional information or have any
   36.26 + * questions.
   36.27 + */
   36.28 +
   36.29 +/*
   36.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   36.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   36.32 + *
   36.33 + *   The original version of this source code and documentation is copyrighted
   36.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   36.35 + * materials are provided under terms of a License Agreement between Taligent
   36.36 + * and Sun. This technology is protected by multiple US and International
   36.37 + * patents. This notice and attribution to Taligent may not be removed.
   36.38 + *   Taligent is a registered trademark of Taligent, Inc.
   36.39 + *
   36.40 + */
   36.41 +
   36.42 +package java.text;
   36.43 +
   36.44 +/**
   36.45 + * Signals that an error has been reached unexpectedly
   36.46 + * while parsing.
   36.47 + * @see java.lang.Exception
   36.48 + * @see java.text.Format
   36.49 + * @see java.text.FieldPosition
   36.50 + * @author      Mark Davis
   36.51 + */
   36.52 +public
   36.53 +class ParseException extends Exception {
   36.54 +
   36.55 +    /**
   36.56 +     * Constructs a ParseException with the specified detail message and
   36.57 +     * offset.
   36.58 +     * A detail message is a String that describes this particular exception.
   36.59 +     * @param s the detail message
   36.60 +     * @param errorOffset the position where the error is found while parsing.
   36.61 +     */
   36.62 +    public ParseException(String s, int errorOffset) {
   36.63 +        super(s);
   36.64 +        this.errorOffset = errorOffset;
   36.65 +    }
   36.66 +
   36.67 +    /**
   36.68 +     * Returns the position where the error was found.
   36.69 +     */
   36.70 +    public int getErrorOffset () {
   36.71 +        return errorOffset;
   36.72 +    }
   36.73 +
   36.74 +    //============ privates ============
   36.75 +    /**
   36.76 +     * The zero-based character offset into the string being parsed at which
   36.77 +     * the error was found during parsing.
   36.78 +     * @serial
   36.79 +     */
   36.80 +    private int errorOffset;
   36.81 +}
    37.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    37.2 +++ b/rt/emul/compact/src/main/java/java/text/ParsePosition.java	Thu Oct 03 15:40:35 2013 +0200
    37.3 @@ -0,0 +1,139 @@
    37.4 +/*
    37.5 + * Copyright (c) 1996, 2002, Oracle and/or its affiliates. All rights reserved.
    37.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    37.7 + *
    37.8 + * This code is free software; you can redistribute it and/or modify it
    37.9 + * under the terms of the GNU General Public License version 2 only, as
   37.10 + * published by the Free Software Foundation.  Oracle designates this
   37.11 + * particular file as subject to the "Classpath" exception as provided
   37.12 + * by Oracle in the LICENSE file that accompanied this code.
   37.13 + *
   37.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   37.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   37.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   37.17 + * version 2 for more details (a copy is included in the LICENSE file that
   37.18 + * accompanied this code).
   37.19 + *
   37.20 + * You should have received a copy of the GNU General Public License version
   37.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   37.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   37.23 + *
   37.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   37.25 + * or visit www.oracle.com if you need additional information or have any
   37.26 + * questions.
   37.27 + */
   37.28 +
   37.29 +/*
   37.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   37.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   37.32 + *
   37.33 + *   The original version of this source code and documentation is copyrighted
   37.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   37.35 + * materials are provided under terms of a License Agreement between Taligent
   37.36 + * and Sun. This technology is protected by multiple US and International
   37.37 + * patents. This notice and attribution to Taligent may not be removed.
   37.38 + *   Taligent is a registered trademark of Taligent, Inc.
   37.39 + *
   37.40 + */
   37.41 +
   37.42 +package java.text;
   37.43 +
   37.44 +
   37.45 +/**
   37.46 + * <code>ParsePosition</code> is a simple class used by <code>Format</code>
   37.47 + * and its subclasses to keep track of the current position during parsing.
   37.48 + * The <code>parseObject</code> method in the various <code>Format</code>
   37.49 + * classes requires a <code>ParsePosition</code> object as an argument.
   37.50 + *
   37.51 + * <p>
   37.52 + * By design, as you parse through a string with different formats,
   37.53 + * you can use the same <code>ParsePosition</code>, since the index parameter
   37.54 + * records the current position.
   37.55 + *
   37.56 + * @author      Mark Davis
   37.57 + * @see         java.text.Format
   37.58 + */
   37.59 +
   37.60 +public class ParsePosition {
   37.61 +
   37.62 +    /**
   37.63 +     * Input: the place you start parsing.
   37.64 +     * <br>Output: position where the parse stopped.
   37.65 +     * This is designed to be used serially,
   37.66 +     * with each call setting index up for the next one.
   37.67 +     */
   37.68 +    int index = 0;
   37.69 +    int errorIndex = -1;
   37.70 +
   37.71 +    /**
   37.72 +     * Retrieve the current parse position.  On input to a parse method, this
   37.73 +     * is the index of the character at which parsing will begin; on output, it
   37.74 +     * is the index of the character following the last character parsed.
   37.75 +     */
   37.76 +    public int getIndex() {
   37.77 +        return index;
   37.78 +    }
   37.79 +
   37.80 +    /**
   37.81 +     * Set the current parse position.
   37.82 +     */
   37.83 +    public void setIndex(int index) {
   37.84 +        this.index = index;
   37.85 +    }
   37.86 +
   37.87 +    /**
   37.88 +     * Create a new ParsePosition with the given initial index.
   37.89 +     */
   37.90 +    public ParsePosition(int index) {
   37.91 +        this.index = index;
   37.92 +    }
   37.93 +    /**
   37.94 +     * Set the index at which a parse error occurred.  Formatters
   37.95 +     * should set this before returning an error code from their
   37.96 +     * parseObject method.  The default value is -1 if this is not set.
   37.97 +     * @since 1.2
   37.98 +     */
   37.99 +    public void setErrorIndex(int ei)
  37.100 +    {
  37.101 +        errorIndex = ei;
  37.102 +    }
  37.103 +
  37.104 +    /**
  37.105 +     * Retrieve the index at which an error occurred, or -1 if the
  37.106 +     * error index has not been set.
  37.107 +     * @since 1.2
  37.108 +     */
  37.109 +    public int getErrorIndex()
  37.110 +    {
  37.111 +        return errorIndex;
  37.112 +    }
  37.113 +    /**
  37.114 +     * Overrides equals
  37.115 +     */
  37.116 +    public boolean equals(Object obj)
  37.117 +    {
  37.118 +        if (obj == null) return false;
  37.119 +        if (!(obj instanceof ParsePosition))
  37.120 +            return false;
  37.121 +        ParsePosition other = (ParsePosition) obj;
  37.122 +        return (index == other.index && errorIndex == other.errorIndex);
  37.123 +    }
  37.124 +
  37.125 +    /**
  37.126 +     * Returns a hash code for this ParsePosition.
  37.127 +     * @return a hash code value for this object
  37.128 +     */
  37.129 +    public int hashCode() {
  37.130 +        return (errorIndex << 16) | index;
  37.131 +    }
  37.132 +
  37.133 +    /**
  37.134 +     * Return a string representation of this ParsePosition.
  37.135 +     * @return  a string representation of this object
  37.136 +     */
  37.137 +    public String toString() {
  37.138 +        return getClass().getName() +
  37.139 +            "[index=" + index +
  37.140 +            ",errorIndex=" + errorIndex + ']';
  37.141 +    }
  37.142 +}
    38.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    38.2 +++ b/rt/emul/compact/src/main/java/java/text/SimpleDateFormat.java	Thu Oct 03 15:40:35 2013 +0200
    38.3 @@ -0,0 +1,2350 @@
    38.4 +/*
    38.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    38.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    38.7 + *
    38.8 + * This code is free software; you can redistribute it and/or modify it
    38.9 + * under the terms of the GNU General Public License version 2 only, as
   38.10 + * published by the Free Software Foundation.  Oracle designates this
   38.11 + * particular file as subject to the "Classpath" exception as provided
   38.12 + * by Oracle in the LICENSE file that accompanied this code.
   38.13 + *
   38.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   38.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   38.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   38.17 + * version 2 for more details (a copy is included in the LICENSE file that
   38.18 + * accompanied this code).
   38.19 + *
   38.20 + * You should have received a copy of the GNU General Public License version
   38.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   38.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   38.23 + *
   38.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   38.25 + * or visit www.oracle.com if you need additional information or have any
   38.26 + * questions.
   38.27 + */
   38.28 +
   38.29 +/*
   38.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   38.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
   38.32 + *
   38.33 + *   The original version of this source code and documentation is copyrighted
   38.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   38.35 + * materials are provided under terms of a License Agreement between Taligent
   38.36 + * and Sun. This technology is protected by multiple US and International
   38.37 + * patents. This notice and attribution to Taligent may not be removed.
   38.38 + *   Taligent is a registered trademark of Taligent, Inc.
   38.39 + *
   38.40 + */
   38.41 +
   38.42 +package java.text;
   38.43 +
   38.44 +import java.io.IOException;
   38.45 +import java.io.InvalidObjectException;
   38.46 +import java.io.ObjectInputStream;
   38.47 +import java.util.Calendar;
   38.48 +import java.util.Date;
   38.49 +import java.util.GregorianCalendar;
   38.50 +import java.util.Locale;
   38.51 +import java.util.Map;
   38.52 +import java.util.MissingResourceException;
   38.53 +import java.util.ResourceBundle;
   38.54 +import java.util.SimpleTimeZone;
   38.55 +import java.util.TimeZone;
   38.56 +import java.util.concurrent.ConcurrentHashMap;
   38.57 +import java.util.concurrent.ConcurrentMap;
   38.58 +import sun.util.calendar.CalendarUtils;
   38.59 +import sun.util.calendar.ZoneInfoFile;
   38.60 +import sun.util.resources.LocaleData;
   38.61 +
   38.62 +import static java.text.DateFormatSymbols.*;
   38.63 +
   38.64 +/**
   38.65 + * <code>SimpleDateFormat</code> is a concrete class for formatting and
   38.66 + * parsing dates in a locale-sensitive manner. It allows for formatting
   38.67 + * (date -> text), parsing (text -> date), and normalization.
   38.68 + *
   38.69 + * <p>
   38.70 + * <code>SimpleDateFormat</code> allows you to start by choosing
   38.71 + * any user-defined patterns for date-time formatting. However, you
   38.72 + * are encouraged to create a date-time formatter with either
   38.73 + * <code>getTimeInstance</code>, <code>getDateInstance</code>, or
   38.74 + * <code>getDateTimeInstance</code> in <code>DateFormat</code>. Each
   38.75 + * of these class methods can return a date/time formatter initialized
   38.76 + * with a default format pattern. You may modify the format pattern
   38.77 + * using the <code>applyPattern</code> methods as desired.
   38.78 + * For more information on using these methods, see
   38.79 + * {@link DateFormat}.
   38.80 + *
   38.81 + * <h4>Date and Time Patterns</h4>
   38.82 + * <p>
   38.83 + * Date and time formats are specified by <em>date and time pattern</em>
   38.84 + * strings.
   38.85 + * Within date and time pattern strings, unquoted letters from
   38.86 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
   38.87 + * <code>'z'</code> are interpreted as pattern letters representing the
   38.88 + * components of a date or time string.
   38.89 + * Text can be quoted using single quotes (<code>'</code>) to avoid
   38.90 + * interpretation.
   38.91 + * <code>"''"</code> represents a single quote.
   38.92 + * All other characters are not interpreted; they're simply copied into the
   38.93 + * output string during formatting or matched against the input string
   38.94 + * during parsing.
   38.95 + * <p>
   38.96 + * The following pattern letters are defined (all other characters from
   38.97 + * <code>'A'</code> to <code>'Z'</code> and from <code>'a'</code> to
   38.98 + * <code>'z'</code> are reserved):
   38.99 + * <blockquote>
  38.100 + * <table border=0 cellspacing=3 cellpadding=0 summary="Chart shows pattern letters, date/time component, presentation, and examples.">
  38.101 + *     <tr bgcolor="#ccccff">
  38.102 + *         <th align=left>Letter
  38.103 + *         <th align=left>Date or Time Component
  38.104 + *         <th align=left>Presentation
  38.105 + *         <th align=left>Examples
  38.106 + *     <tr>
  38.107 + *         <td><code>G</code>
  38.108 + *         <td>Era designator
  38.109 + *         <td><a href="#text">Text</a>
  38.110 + *         <td><code>AD</code>
  38.111 + *     <tr bgcolor="#eeeeff">
  38.112 + *         <td><code>y</code>
  38.113 + *         <td>Year
  38.114 + *         <td><a href="#year">Year</a>
  38.115 + *         <td><code>1996</code>; <code>96</code>
  38.116 + *     <tr>
  38.117 + *         <td><code>Y</code>
  38.118 + *         <td>Week year
  38.119 + *         <td><a href="#year">Year</a>
  38.120 + *         <td><code>2009</code>; <code>09</code>
  38.121 + *     <tr bgcolor="#eeeeff">
  38.122 + *         <td><code>M</code>
  38.123 + *         <td>Month in year
  38.124 + *         <td><a href="#month">Month</a>
  38.125 + *         <td><code>July</code>; <code>Jul</code>; <code>07</code>
  38.126 + *     <tr>
  38.127 + *         <td><code>w</code>
  38.128 + *         <td>Week in year
  38.129 + *         <td><a href="#number">Number</a>
  38.130 + *         <td><code>27</code>
  38.131 + *     <tr bgcolor="#eeeeff">
  38.132 + *         <td><code>W</code>
  38.133 + *         <td>Week in month
  38.134 + *         <td><a href="#number">Number</a>
  38.135 + *         <td><code>2</code>
  38.136 + *     <tr>
  38.137 + *         <td><code>D</code>
  38.138 + *         <td>Day in year
  38.139 + *         <td><a href="#number">Number</a>
  38.140 + *         <td><code>189</code>
  38.141 + *     <tr bgcolor="#eeeeff">
  38.142 + *         <td><code>d</code>
  38.143 + *         <td>Day in month
  38.144 + *         <td><a href="#number">Number</a>
  38.145 + *         <td><code>10</code>
  38.146 + *     <tr>
  38.147 + *         <td><code>F</code>
  38.148 + *         <td>Day of week in month
  38.149 + *         <td><a href="#number">Number</a>
  38.150 + *         <td><code>2</code>
  38.151 + *     <tr bgcolor="#eeeeff">
  38.152 + *         <td><code>E</code>
  38.153 + *         <td>Day name in week
  38.154 + *         <td><a href="#text">Text</a>
  38.155 + *         <td><code>Tuesday</code>; <code>Tue</code>
  38.156 + *     <tr>
  38.157 + *         <td><code>u</code>
  38.158 + *         <td>Day number of week (1 = Monday, ..., 7 = Sunday)
  38.159 + *         <td><a href="#number">Number</a>
  38.160 + *         <td><code>1</code>
  38.161 + *     <tr bgcolor="#eeeeff">
  38.162 + *         <td><code>a</code>
  38.163 + *         <td>Am/pm marker
  38.164 + *         <td><a href="#text">Text</a>
  38.165 + *         <td><code>PM</code>
  38.166 + *     <tr>
  38.167 + *         <td><code>H</code>
  38.168 + *         <td>Hour in day (0-23)
  38.169 + *         <td><a href="#number">Number</a>
  38.170 + *         <td><code>0</code>
  38.171 + *     <tr bgcolor="#eeeeff">
  38.172 + *         <td><code>k</code>
  38.173 + *         <td>Hour in day (1-24)
  38.174 + *         <td><a href="#number">Number</a>
  38.175 + *         <td><code>24</code>
  38.176 + *     <tr>
  38.177 + *         <td><code>K</code>
  38.178 + *         <td>Hour in am/pm (0-11)
  38.179 + *         <td><a href="#number">Number</a>
  38.180 + *         <td><code>0</code>
  38.181 + *     <tr bgcolor="#eeeeff">
  38.182 + *         <td><code>h</code>
  38.183 + *         <td>Hour in am/pm (1-12)
  38.184 + *         <td><a href="#number">Number</a>
  38.185 + *         <td><code>12</code>
  38.186 + *     <tr>
  38.187 + *         <td><code>m</code>
  38.188 + *         <td>Minute in hour
  38.189 + *         <td><a href="#number">Number</a>
  38.190 + *         <td><code>30</code>
  38.191 + *     <tr bgcolor="#eeeeff">
  38.192 + *         <td><code>s</code>
  38.193 + *         <td>Second in minute
  38.194 + *         <td><a href="#number">Number</a>
  38.195 + *         <td><code>55</code>
  38.196 + *     <tr>
  38.197 + *         <td><code>S</code>
  38.198 + *         <td>Millisecond
  38.199 + *         <td><a href="#number">Number</a>
  38.200 + *         <td><code>978</code>
  38.201 + *     <tr bgcolor="#eeeeff">
  38.202 + *         <td><code>z</code>
  38.203 + *         <td>Time zone
  38.204 + *         <td><a href="#timezone">General time zone</a>
  38.205 + *         <td><code>Pacific Standard Time</code>; <code>PST</code>; <code>GMT-08:00</code>
  38.206 + *     <tr>
  38.207 + *         <td><code>Z</code>
  38.208 + *         <td>Time zone
  38.209 + *         <td><a href="#rfc822timezone">RFC 822 time zone</a>
  38.210 + *         <td><code>-0800</code>
  38.211 + *     <tr bgcolor="#eeeeff">
  38.212 + *         <td><code>X</code>
  38.213 + *         <td>Time zone
  38.214 + *         <td><a href="#iso8601timezone">ISO 8601 time zone</a>
  38.215 + *         <td><code>-08</code>; <code>-0800</code>;  <code>-08:00</code>
  38.216 + * </table>
  38.217 + * </blockquote>
  38.218 + * Pattern letters are usually repeated, as their number determines the
  38.219 + * exact presentation:
  38.220 + * <ul>
  38.221 + * <li><strong><a name="text">Text:</a></strong>
  38.222 + *     For formatting, if the number of pattern letters is 4 or more,
  38.223 + *     the full form is used; otherwise a short or abbreviated form
  38.224 + *     is used if available.
  38.225 + *     For parsing, both forms are accepted, independent of the number
  38.226 + *     of pattern letters.<br><br></li>
  38.227 + * <li><strong><a name="number">Number:</a></strong>
  38.228 + *     For formatting, the number of pattern letters is the minimum
  38.229 + *     number of digits, and shorter numbers are zero-padded to this amount.
  38.230 + *     For parsing, the number of pattern letters is ignored unless
  38.231 + *     it's needed to separate two adjacent fields.<br><br></li>
  38.232 + * <li><strong><a name="year">Year:</a></strong>
  38.233 + *     If the formatter's {@link #getCalendar() Calendar} is the Gregorian
  38.234 + *     calendar, the following rules are applied.<br>
  38.235 + *     <ul>
  38.236 + *     <li>For formatting, if the number of pattern letters is 2, the year
  38.237 + *         is truncated to 2 digits; otherwise it is interpreted as a
  38.238 + *         <a href="#number">number</a>.
  38.239 + *     <li>For parsing, if the number of pattern letters is more than 2,
  38.240 + *         the year is interpreted literally, regardless of the number of
  38.241 + *         digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to
  38.242 + *         Jan 11, 12 A.D.
  38.243 + *     <li>For parsing with the abbreviated year pattern ("y" or "yy"),
  38.244 + *         <code>SimpleDateFormat</code> must interpret the abbreviated year
  38.245 + *         relative to some century.  It does this by adjusting dates to be
  38.246 + *         within 80 years before and 20 years after the time the <code>SimpleDateFormat</code>
  38.247 + *         instance is created. For example, using a pattern of "MM/dd/yy" and a
  38.248 + *         <code>SimpleDateFormat</code> instance created on Jan 1, 1997,  the string
  38.249 + *         "01/11/12" would be interpreted as Jan 11, 2012 while the string "05/04/64"
  38.250 + *         would be interpreted as May 4, 1964.
  38.251 + *         During parsing, only strings consisting of exactly two digits, as defined by
  38.252 + *         {@link Character#isDigit(char)}, will be parsed into the default century.
  38.253 + *         Any other numeric string, such as a one digit string, a three or more digit
  38.254 + *         string, or a two digit string that isn't all digits (for example, "-1"), is
  38.255 + *         interpreted literally.  So "01/02/3" or "01/02/003" are parsed, using the
  38.256 + *         same pattern, as Jan 2, 3 AD.  Likewise, "01/02/-3" is parsed as Jan 2, 4 BC.
  38.257 + *     </ul>
  38.258 + *     Otherwise, calendar system specific forms are applied.
  38.259 + *     For both formatting and parsing, if the number of pattern
  38.260 + *     letters is 4 or more, a calendar specific {@linkplain
  38.261 + *     Calendar#LONG long form} is used. Otherwise, a calendar
  38.262 + *     specific {@linkplain Calendar#SHORT short or abbreviated form}
  38.263 + *     is used.<br>
  38.264 + *     <br>
  38.265 + *     If week year {@code 'Y'} is specified and the {@linkplain
  38.266 + *     #getCalendar() calendar} doesn't support any <a
  38.267 + *     href="../util/GregorianCalendar.html#week_year"> week
  38.268 + *     years</a>, the calendar year ({@code 'y'}) is used instead. The
  38.269 + *     support of week years can be tested with a call to {@link
  38.270 + *     DateFormat#getCalendar() getCalendar()}.{@link
  38.271 + *     java.util.Calendar#isWeekDateSupported()
  38.272 + *     isWeekDateSupported()}.<br><br></li>
  38.273 + * <li><strong><a name="month">Month:</a></strong>
  38.274 + *     If the number of pattern letters is 3 or more, the month is
  38.275 + *     interpreted as <a href="#text">text</a>; otherwise,
  38.276 + *     it is interpreted as a <a href="#number">number</a>.<br><br></li>
  38.277 + * <li><strong><a name="timezone">General time zone:</a></strong>
  38.278 + *     Time zones are interpreted as <a href="#text">text</a> if they have
  38.279 + *     names. For time zones representing a GMT offset value, the
  38.280 + *     following syntax is used:
  38.281 + *     <pre>
  38.282 + *     <a name="GMTOffsetTimeZone"><i>GMTOffsetTimeZone:</i></a>
  38.283 + *             <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
  38.284 + *     <i>Sign:</i> one of
  38.285 + *             <code>+ -</code>
  38.286 + *     <i>Hours:</i>
  38.287 + *             <i>Digit</i>
  38.288 + *             <i>Digit</i> <i>Digit</i>
  38.289 + *     <i>Minutes:</i>
  38.290 + *             <i>Digit</i> <i>Digit</i>
  38.291 + *     <i>Digit:</i> one of
  38.292 + *             <code>0 1 2 3 4 5 6 7 8 9</code></pre>
  38.293 + *     <i>Hours</i> must be between 0 and 23, and <i>Minutes</i> must be between
  38.294 + *     00 and 59. The format is locale independent and digits must be taken
  38.295 + *     from the Basic Latin block of the Unicode standard.
  38.296 + *     <p>For parsing, <a href="#rfc822timezone">RFC 822 time zones</a> are also
  38.297 + *     accepted.<br><br></li>
  38.298 + * <li><strong><a name="rfc822timezone">RFC 822 time zone:</a></strong>
  38.299 + *     For formatting, the RFC 822 4-digit time zone format is used:
  38.300 + *
  38.301 + *     <pre>
  38.302 + *     <i>RFC822TimeZone:</i>
  38.303 + *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
  38.304 + *     <i>TwoDigitHours:</i>
  38.305 + *             <i>Digit Digit</i></pre>
  38.306 + *     <i>TwoDigitHours</i> must be between 00 and 23. Other definitions
  38.307 + *     are as for <a href="#timezone">general time zones</a>.
  38.308 + *
  38.309 + *     <p>For parsing, <a href="#timezone">general time zones</a> are also
  38.310 + *     accepted.
  38.311 + * <li><strong><a name="iso8601timezone">ISO 8601 Time zone:</a></strong>
  38.312 + *     The number of pattern letters designates the format for both formatting
  38.313 + *     and parsing as follows:
  38.314 + *     <pre>
  38.315 + *     <i>ISO8601TimeZone:</i>
  38.316 + *             <i>OneLetterISO8601TimeZone</i>
  38.317 + *             <i>TwoLetterISO8601TimeZone</i>
  38.318 + *             <i>ThreeLetterISO8601TimeZone</i>
  38.319 + *     <i>OneLetterISO8601TimeZone:</i>
  38.320 + *             <i>Sign</i> <i>TwoDigitHours</i>
  38.321 + *             {@code Z}
  38.322 + *     <i>TwoLetterISO8601TimeZone:</i>
  38.323 + *             <i>Sign</i> <i>TwoDigitHours</i> <i>Minutes</i>
  38.324 + *             {@code Z}
  38.325 + *     <i>ThreeLetterISO8601TimeZone:</i>
  38.326 + *             <i>Sign</i> <i>TwoDigitHours</i> {@code :} <i>Minutes</i>
  38.327 + *             {@code Z}</pre>
  38.328 + *     Other definitions are as for <a href="#timezone">general time zones</a> or
  38.329 + *     <a href="#rfc822timezone">RFC 822 time zones</a>.
  38.330 + *
  38.331 + *     <p>For formatting, if the offset value from GMT is 0, {@code "Z"} is
  38.332 + *     produced. If the number of pattern letters is 1, any fraction of an hour
  38.333 + *     is ignored. For example, if the pattern is {@code "X"} and the time zone is
  38.334 + *     {@code "GMT+05:30"}, {@code "+05"} is produced.
  38.335 + *
  38.336 + *     <p>For parsing, {@code "Z"} is parsed as the UTC time zone designator.
  38.337 + *     <a href="#timezone">General time zones</a> are <em>not</em> accepted.
  38.338 + *
  38.339 + *     <p>If the number of pattern letters is 4 or more, {@link
  38.340 + *     IllegalArgumentException} is thrown when constructing a {@code
  38.341 + *     SimpleDateFormat} or {@linkplain #applyPattern(String) applying a
  38.342 + *     pattern}.
  38.343 + * </ul>
  38.344 + * <code>SimpleDateFormat</code> also supports <em>localized date and time
  38.345 + * pattern</em> strings. In these strings, the pattern letters described above
  38.346 + * may be replaced with other, locale dependent, pattern letters.
  38.347 + * <code>SimpleDateFormat</code> does not deal with the localization of text
  38.348 + * other than the pattern letters; that's up to the client of the class.
  38.349 + * <p>
  38.350 + *
  38.351 + * <h4>Examples</h4>
  38.352 + *
  38.353 + * The following examples show how date and time patterns are interpreted in
  38.354 + * the U.S. locale. The given date and time are 2001-07-04 12:08:56 local time
  38.355 + * in the U.S. Pacific Time time zone.
  38.356 + * <blockquote>
  38.357 + * <table border=0 cellspacing=3 cellpadding=0 summary="Examples of date and time patterns interpreted in the U.S. locale">
  38.358 + *     <tr bgcolor="#ccccff">
  38.359 + *         <th align=left>Date and Time Pattern
  38.360 + *         <th align=left>Result
  38.361 + *     <tr>
  38.362 + *         <td><code>"yyyy.MM.dd G 'at' HH:mm:ss z"</code>
  38.363 + *         <td><code>2001.07.04 AD at 12:08:56 PDT</code>
  38.364 + *     <tr bgcolor="#eeeeff">
  38.365 + *         <td><code>"EEE, MMM d, ''yy"</code>
  38.366 + *         <td><code>Wed, Jul 4, '01</code>
  38.367 + *     <tr>
  38.368 + *         <td><code>"h:mm a"</code>
  38.369 + *         <td><code>12:08 PM</code>
  38.370 + *     <tr bgcolor="#eeeeff">
  38.371 + *         <td><code>"hh 'o''clock' a, zzzz"</code>
  38.372 + *         <td><code>12 o'clock PM, Pacific Daylight Time</code>
  38.373 + *     <tr>
  38.374 + *         <td><code>"K:mm a, z"</code>
  38.375 + *         <td><code>0:08 PM, PDT</code>
  38.376 + *     <tr bgcolor="#eeeeff">
  38.377 + *         <td><code>"yyyyy.MMMMM.dd GGG hh:mm aaa"</code>
  38.378 + *         <td><code>02001.July.04 AD 12:08 PM</code>
  38.379 + *     <tr>
  38.380 + *         <td><code>"EEE, d MMM yyyy HH:mm:ss Z"</code>
  38.381 + *         <td><code>Wed, 4 Jul 2001 12:08:56 -0700</code>
  38.382 + *     <tr bgcolor="#eeeeff">
  38.383 + *         <td><code>"yyMMddHHmmssZ"</code>
  38.384 + *         <td><code>010704120856-0700</code>
  38.385 + *     <tr>
  38.386 + *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSZ"</code>
  38.387 + *         <td><code>2001-07-04T12:08:56.235-0700</code>
  38.388 + *     <tr bgcolor="#eeeeff">
  38.389 + *         <td><code>"yyyy-MM-dd'T'HH:mm:ss.SSSXXX"</code>
  38.390 + *         <td><code>2001-07-04T12:08:56.235-07:00</code>
  38.391 + *     <tr>
  38.392 + *         <td><code>"YYYY-'W'ww-u"</code>
  38.393 + *         <td><code>2001-W27-3</code>
  38.394 + * </table>
  38.395 + * </blockquote>
  38.396 + *
  38.397 + * <h4><a name="synchronization">Synchronization</a></h4>
  38.398 + *
  38.399 + * <p>
  38.400 + * Date formats are not synchronized.
  38.401 + * It is recommended to create separate format instances for each thread.
  38.402 + * If multiple threads access a format concurrently, it must be synchronized
  38.403 + * externally.
  38.404 + *
  38.405 + * @see          <a href="http://java.sun.com/docs/books/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a>
  38.406 + * @see          java.util.Calendar
  38.407 + * @see          java.util.TimeZone
  38.408 + * @see          DateFormat
  38.409 + * @see          DateFormatSymbols
  38.410 + * @author       Mark Davis, Chen-Lieh Huang, Alan Liu
  38.411 + */
  38.412 +public class SimpleDateFormat extends DateFormat {
  38.413 +
  38.414 +    // the official serial version ID which says cryptically
  38.415 +    // which version we're compatible with
  38.416 +    static final long serialVersionUID = 4774881970558875024L;
  38.417 +
  38.418 +    // the internal serial version which says which version was written
  38.419 +    // - 0 (default) for version up to JDK 1.1.3
  38.420 +    // - 1 for version from JDK 1.1.4, which includes a new field
  38.421 +    static final int currentSerialVersion = 1;
  38.422 +
  38.423 +    /**
  38.424 +     * The version of the serialized data on the stream.  Possible values:
  38.425 +     * <ul>
  38.426 +     * <li><b>0</b> or not present on stream: JDK 1.1.3.  This version
  38.427 +     * has no <code>defaultCenturyStart</code> on stream.
  38.428 +     * <li><b>1</b> JDK 1.1.4 or later.  This version adds
  38.429 +     * <code>defaultCenturyStart</code>.
  38.430 +     * </ul>
  38.431 +     * When streaming out this class, the most recent format
  38.432 +     * and the highest allowable <code>serialVersionOnStream</code>
  38.433 +     * is written.
  38.434 +     * @serial
  38.435 +     * @since JDK1.1.4
  38.436 +     */
  38.437 +    private int serialVersionOnStream = currentSerialVersion;
  38.438 +
  38.439 +    /**
  38.440 +     * The pattern string of this formatter.  This is always a non-localized
  38.441 +     * pattern.  May not be null.  See class documentation for details.
  38.442 +     * @serial
  38.443 +     */
  38.444 +    private String pattern;
  38.445 +
  38.446 +    /**
  38.447 +     * Saved numberFormat and pattern.
  38.448 +     * @see SimpleDateFormat#checkNegativeNumberExpression
  38.449 +     */
  38.450 +    transient private NumberFormat originalNumberFormat;
  38.451 +    transient private String originalNumberPattern;
  38.452 +
  38.453 +    /**
  38.454 +     * The minus sign to be used with format and parse.
  38.455 +     */
  38.456 +    transient private char minusSign = '-';
  38.457 +
  38.458 +    /**
  38.459 +     * True when a negative sign follows a number.
  38.460 +     * (True as default in Arabic.)
  38.461 +     */
  38.462 +    transient private boolean hasFollowingMinusSign = false;
  38.463 +
  38.464 +    /**
  38.465 +     * The compiled pattern.
  38.466 +     */
  38.467 +    transient private char[] compiledPattern;
  38.468 +
  38.469 +    /**
  38.470 +     * Tags for the compiled pattern.
  38.471 +     */
  38.472 +    private final static int TAG_QUOTE_ASCII_CHAR       = 100;
  38.473 +    private final static int TAG_QUOTE_CHARS            = 101;
  38.474 +
  38.475 +    /**
  38.476 +     * Locale dependent digit zero.
  38.477 +     * @see #zeroPaddingNumber
  38.478 +     * @see java.text.DecimalFormatSymbols#getZeroDigit
  38.479 +     */
  38.480 +    transient private char zeroDigit;
  38.481 +
  38.482 +    /**
  38.483 +     * The symbols used by this formatter for week names, month names,
  38.484 +     * etc.  May not be null.
  38.485 +     * @serial
  38.486 +     * @see java.text.DateFormatSymbols
  38.487 +     */
  38.488 +    private DateFormatSymbols formatData;
  38.489 +
  38.490 +    /**
  38.491 +     * We map dates with two-digit years into the century starting at
  38.492 +     * <code>defaultCenturyStart</code>, which may be any date.  May
  38.493 +     * not be null.
  38.494 +     * @serial
  38.495 +     * @since JDK1.1.4
  38.496 +     */
  38.497 +    private Date defaultCenturyStart;
  38.498 +
  38.499 +    transient private int defaultCenturyStartYear;
  38.500 +
  38.501 +    private static final int MILLIS_PER_MINUTE = 60 * 1000;
  38.502 +
  38.503 +    // For time zones that have no names, use strings GMT+minutes and
  38.504 +    // GMT-minutes. For instance, in France the time zone is GMT+60.
  38.505 +    private static final String GMT = "GMT";
  38.506 +
  38.507 +    /**
  38.508 +     * Cache to hold the DateTimePatterns of a Locale.
  38.509 +     */
  38.510 +    private static final ConcurrentMap<Locale, String[]> cachedLocaleData
  38.511 +        = new ConcurrentHashMap<Locale, String[]>(3);
  38.512 +
  38.513 +    /**
  38.514 +     * Cache NumberFormat instances with Locale key.
  38.515 +     */
  38.516 +    private static final ConcurrentMap<Locale, NumberFormat> cachedNumberFormatData
  38.517 +        = new ConcurrentHashMap<Locale, NumberFormat>(3);
  38.518 +
  38.519 +    /**
  38.520 +     * The Locale used to instantiate this
  38.521 +     * <code>SimpleDateFormat</code>. The value may be null if this object
  38.522 +     * has been created by an older <code>SimpleDateFormat</code> and
  38.523 +     * deserialized.
  38.524 +     *
  38.525 +     * @serial
  38.526 +     * @since 1.6
  38.527 +     */
  38.528 +    private Locale locale;
  38.529 +
  38.530 +    /**
  38.531 +     * Indicates whether this <code>SimpleDateFormat</code> should use
  38.532 +     * the DateFormatSymbols. If true, the format and parse methods
  38.533 +     * use the DateFormatSymbols values. If false, the format and
  38.534 +     * parse methods call Calendar.getDisplayName or
  38.535 +     * Calendar.getDisplayNames.
  38.536 +     */
  38.537 +    transient boolean useDateFormatSymbols;
  38.538 +
  38.539 +    /**
  38.540 +     * Constructs a <code>SimpleDateFormat</code> using the default pattern and
  38.541 +     * date format symbols for the default locale.
  38.542 +     * <b>Note:</b> This constructor may not support all locales.
  38.543 +     * For full coverage, use the factory methods in the {@link DateFormat}
  38.544 +     * class.
  38.545 +     */
  38.546 +    public SimpleDateFormat() {
  38.547 +        this(SHORT, SHORT, Locale.getDefault(Locale.Category.FORMAT));
  38.548 +    }
  38.549 +
  38.550 +    /**
  38.551 +     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
  38.552 +     * the default date format symbols for the default locale.
  38.553 +     * <b>Note:</b> This constructor may not support all locales.
  38.554 +     * For full coverage, use the factory methods in the {@link DateFormat}
  38.555 +     * class.
  38.556 +     *
  38.557 +     * @param pattern the pattern describing the date and time format
  38.558 +     * @exception NullPointerException if the given pattern is null
  38.559 +     * @exception IllegalArgumentException if the given pattern is invalid
  38.560 +     */
  38.561 +    public SimpleDateFormat(String pattern)
  38.562 +    {
  38.563 +        this(pattern, Locale.getDefault(Locale.Category.FORMAT));
  38.564 +    }
  38.565 +
  38.566 +    /**
  38.567 +     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
  38.568 +     * the default date format symbols for the given locale.
  38.569 +     * <b>Note:</b> This constructor may not support all locales.
  38.570 +     * For full coverage, use the factory methods in the {@link DateFormat}
  38.571 +     * class.
  38.572 +     *
  38.573 +     * @param pattern the pattern describing the date and time format
  38.574 +     * @param locale the locale whose date format symbols should be used
  38.575 +     * @exception NullPointerException if the given pattern or locale is null
  38.576 +     * @exception IllegalArgumentException if the given pattern is invalid
  38.577 +     */
  38.578 +    public SimpleDateFormat(String pattern, Locale locale)
  38.579 +    {
  38.580 +        if (pattern == null || locale == null) {
  38.581 +            throw new NullPointerException();
  38.582 +        }
  38.583 +
  38.584 +        initializeCalendar(locale);
  38.585 +        this.pattern = pattern;
  38.586 +        this.formatData = DateFormatSymbols.getInstanceRef(locale);
  38.587 +        this.locale = locale;
  38.588 +        initialize(locale);
  38.589 +    }
  38.590 +
  38.591 +    /**
  38.592 +     * Constructs a <code>SimpleDateFormat</code> using the given pattern and
  38.593 +     * date format symbols.
  38.594 +     *
  38.595 +     * @param pattern the pattern describing the date and time format
  38.596 +     * @param formatSymbols the date format symbols to be used for formatting
  38.597 +     * @exception NullPointerException if the given pattern or formatSymbols is null
  38.598 +     * @exception IllegalArgumentException if the given pattern is invalid
  38.599 +     */
  38.600 +    public SimpleDateFormat(String pattern, DateFormatSymbols formatSymbols)
  38.601 +    {
  38.602 +        if (pattern == null || formatSymbols == null) {
  38.603 +            throw new NullPointerException();
  38.604 +        }
  38.605 +
  38.606 +        this.pattern = pattern;
  38.607 +        this.formatData = (DateFormatSymbols) formatSymbols.clone();
  38.608 +        this.locale = Locale.getDefault(Locale.Category.FORMAT);
  38.609 +        initializeCalendar(this.locale);
  38.610 +        initialize(this.locale);
  38.611 +        useDateFormatSymbols = true;
  38.612 +    }
  38.613 +
  38.614 +    /* Package-private, called by DateFormat factory methods */
  38.615 +    SimpleDateFormat(int timeStyle, int dateStyle, Locale loc) {
  38.616 +        if (loc == null) {
  38.617 +            throw new NullPointerException();
  38.618 +        }
  38.619 +
  38.620 +        this.locale = loc;
  38.621 +        // initialize calendar and related fields
  38.622 +        initializeCalendar(loc);
  38.623 +
  38.624 +        /* try the cache first */
  38.625 +        String[] dateTimePatterns = cachedLocaleData.get(loc);
  38.626 +        if (dateTimePatterns == null) { /* cache miss */
  38.627 +            ResourceBundle r = LocaleData.getDateFormatData(loc);
  38.628 +            if (!isGregorianCalendar()) {
  38.629 +                try {
  38.630 +                    dateTimePatterns = r.getStringArray(getCalendarName() + ".DateTimePatterns");
  38.631 +                } catch (MissingResourceException e) {
  38.632 +                }
  38.633 +            }
  38.634 +            if (dateTimePatterns == null) {
  38.635 +                dateTimePatterns = r.getStringArray("DateTimePatterns");
  38.636 +            }
  38.637 +            /* update cache */
  38.638 +            cachedLocaleData.putIfAbsent(loc, dateTimePatterns);
  38.639 +        }
  38.640 +        formatData = DateFormatSymbols.getInstanceRef(loc);
  38.641 +        if ((timeStyle >= 0) && (dateStyle >= 0)) {
  38.642 +            Object[] dateTimeArgs = {dateTimePatterns[timeStyle],
  38.643 +                                     dateTimePatterns[dateStyle + 4]};
  38.644 +            pattern = MessageFormat.format(dateTimePatterns[8], dateTimeArgs);
  38.645 +        }
  38.646 +        else if (timeStyle >= 0) {
  38.647 +            pattern = dateTimePatterns[timeStyle];
  38.648 +        }
  38.649 +        else if (dateStyle >= 0) {
  38.650 +            pattern = dateTimePatterns[dateStyle + 4];
  38.651 +        }
  38.652 +        else {
  38.653 +            throw new IllegalArgumentException("No date or time style specified");
  38.654 +        }
  38.655 +
  38.656 +        initialize(loc);
  38.657 +    }
  38.658 +
  38.659 +    /* Initialize compiledPattern and numberFormat fields */
  38.660 +    private void initialize(Locale loc) {
  38.661 +        // Verify and compile the given pattern.
  38.662 +        compiledPattern = compile(pattern);
  38.663 +
  38.664 +        /* try the cache first */
  38.665 +        numberFormat = cachedNumberFormatData.get(loc);
  38.666 +        if (numberFormat == null) { /* cache miss */
  38.667 +            numberFormat = NumberFormat.getIntegerInstance(loc);
  38.668 +            numberFormat.setGroupingUsed(false);
  38.669 +
  38.670 +            /* update cache */
  38.671 +            cachedNumberFormatData.putIfAbsent(loc, numberFormat);
  38.672 +        }
  38.673 +        numberFormat = (NumberFormat) numberFormat.clone();
  38.674 +
  38.675 +        initializeDefaultCentury();
  38.676 +    }
  38.677 +
  38.678 +    private void initializeCalendar(Locale loc) {
  38.679 +        if (calendar == null) {
  38.680 +            assert loc != null;
  38.681 +            // The format object must be constructed using the symbols for this zone.
  38.682 +            // However, the calendar should use the current default TimeZone.
  38.683 +            // If this is not contained in the locale zone strings, then the zone
  38.684 +            // will be formatted using generic GMT+/-H:MM nomenclature.
  38.685 +            calendar = Calendar.getInstance(TimeZone.getDefault(), loc);
  38.686 +        }
  38.687 +    }
  38.688 +
  38.689 +    /**
  38.690 +     * Returns the compiled form of the given pattern. The syntax of
  38.691 +     * the compiled pattern is:
  38.692 +     * <blockquote>
  38.693 +     * CompiledPattern:
  38.694 +     *     EntryList
  38.695 +     * EntryList:
  38.696 +     *     Entry
  38.697 +     *     EntryList Entry
  38.698 +     * Entry:
  38.699 +     *     TagField
  38.700 +     *     TagField data
  38.701 +     * TagField:
  38.702 +     *     Tag Length
  38.703 +     *     TaggedData
  38.704 +     * Tag:
  38.705 +     *     pattern_char_index
  38.706 +     *     TAG_QUOTE_CHARS
  38.707 +     * Length:
  38.708 +     *     short_length
  38.709 +     *     long_length
  38.710 +     * TaggedData:
  38.711 +     *     TAG_QUOTE_ASCII_CHAR ascii_char
  38.712 +     *
  38.713 +     * </blockquote>
  38.714 +     *
  38.715 +     * where `short_length' is an 8-bit unsigned integer between 0 and
  38.716 +     * 254.  `long_length' is a sequence of an 8-bit integer 255 and a
  38.717 +     * 32-bit signed integer value which is split into upper and lower
  38.718 +     * 16-bit fields in two char's. `pattern_char_index' is an 8-bit
  38.719 +     * integer between 0 and 18. `ascii_char' is an 7-bit ASCII
  38.720 +     * character value. `data' depends on its Tag value.
  38.721 +     * <p>
  38.722 +     * If Length is short_length, Tag and short_length are packed in a
  38.723 +     * single char, as illustrated below.
  38.724 +     * <blockquote>
  38.725 +     *     char[0] = (Tag << 8) | short_length;
  38.726 +     * </blockquote>
  38.727 +     *
  38.728 +     * If Length is long_length, Tag and 255 are packed in the first
  38.729 +     * char and a 32-bit integer, as illustrated below.
  38.730 +     * <blockquote>
  38.731 +     *     char[0] = (Tag << 8) | 255;
  38.732 +     *     char[1] = (char) (long_length >>> 16);
  38.733 +     *     char[2] = (char) (long_length & 0xffff);
  38.734 +     * </blockquote>
  38.735 +     * <p>
  38.736 +     * If Tag is a pattern_char_index, its Length is the number of
  38.737 +     * pattern characters. For example, if the given pattern is
  38.738 +     * "yyyy", Tag is 1 and Length is 4, followed by no data.
  38.739 +     * <p>
  38.740 +     * If Tag is TAG_QUOTE_CHARS, its Length is the number of char's
  38.741 +     * following the TagField. For example, if the given pattern is
  38.742 +     * "'o''clock'", Length is 7 followed by a char sequence of
  38.743 +     * <code>o&nbs;'&nbs;c&nbs;l&nbs;o&nbs;c&nbs;k</code>.
  38.744 +     * <p>
  38.745 +     * TAG_QUOTE_ASCII_CHAR is a special tag and has an ASCII
  38.746 +     * character in place of Length. For example, if the given pattern
  38.747 +     * is "'o'", the TaggedData entry is
  38.748 +     * <code>((TAG_QUOTE_ASCII_CHAR&nbs;<<&nbs;8)&nbs;|&nbs;'o')</code>.
  38.749 +     *
  38.750 +     * @exception NullPointerException if the given pattern is null
  38.751 +     * @exception IllegalArgumentException if the given pattern is invalid
  38.752 +     */
  38.753 +    private char[] compile(String pattern) {
  38.754 +        int length = pattern.length();
  38.755 +        boolean inQuote = false;
  38.756 +        StringBuilder compiledPattern = new StringBuilder(length * 2);
  38.757 +        StringBuilder tmpBuffer = null;
  38.758 +        int count = 0;
  38.759 +        int lastTag = -1;
  38.760 +
  38.761 +        for (int i = 0; i < length; i++) {
  38.762 +            char c = pattern.charAt(i);
  38.763 +
  38.764 +            if (c == '\'') {
  38.765 +                // '' is treated as a single quote regardless of being
  38.766 +                // in a quoted section.
  38.767 +                if ((i + 1) < length) {
  38.768 +                    c = pattern.charAt(i + 1);
  38.769 +                    if (c == '\'') {
  38.770 +                        i++;
  38.771 +                        if (count != 0) {
  38.772 +                            encode(lastTag, count, compiledPattern);
  38.773 +                            lastTag = -1;
  38.774 +                            count = 0;
  38.775 +                        }
  38.776 +                        if (inQuote) {
  38.777 +                            tmpBuffer.append(c);
  38.778 +                        } else {
  38.779 +                            compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
  38.780 +                        }
  38.781 +                        continue;
  38.782 +                    }
  38.783 +                }
  38.784 +                if (!inQuote) {
  38.785 +                    if (count != 0) {
  38.786 +                        encode(lastTag, count, compiledPattern);
  38.787 +                        lastTag = -1;
  38.788 +                        count = 0;
  38.789 +                    }
  38.790 +                    if (tmpBuffer == null) {
  38.791 +                        tmpBuffer = new StringBuilder(length);
  38.792 +                    } else {
  38.793 +                        tmpBuffer.setLength(0);
  38.794 +                    }
  38.795 +                    inQuote = true;
  38.796 +                } else {
  38.797 +                    int len = tmpBuffer.length();
  38.798 +                    if (len == 1) {
  38.799 +                        char ch = tmpBuffer.charAt(0);
  38.800 +                        if (ch < 128) {
  38.801 +                            compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | ch));
  38.802 +                        } else {
  38.803 +                            compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | 1));
  38.804 +                            compiledPattern.append(ch);
  38.805 +                        }
  38.806 +                    } else {
  38.807 +                        encode(TAG_QUOTE_CHARS, len, compiledPattern);
  38.808 +                        compiledPattern.append(tmpBuffer);
  38.809 +                    }
  38.810 +                    inQuote = false;
  38.811 +                }
  38.812 +                continue;
  38.813 +            }
  38.814 +            if (inQuote) {
  38.815 +                tmpBuffer.append(c);
  38.816 +                continue;
  38.817 +            }
  38.818 +            if (!(c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) {
  38.819 +                if (count != 0) {
  38.820 +                    encode(lastTag, count, compiledPattern);
  38.821 +                    lastTag = -1;
  38.822 +                    count = 0;
  38.823 +                }
  38.824 +                if (c < 128) {
  38.825 +                    // In most cases, c would be a delimiter, such as ':'.
  38.826 +                    compiledPattern.append((char)(TAG_QUOTE_ASCII_CHAR << 8 | c));
  38.827 +                } else {
  38.828 +                    // Take any contiguous non-ASCII alphabet characters and
  38.829 +                    // put them in a single TAG_QUOTE_CHARS.
  38.830 +                    int j;
  38.831 +                    for (j = i + 1; j < length; j++) {
  38.832 +                        char d = pattern.charAt(j);
  38.833 +                        if (d == '\'' || (d >= 'a' && d <= 'z' || d >= 'A' && d <= 'Z')) {
  38.834 +                            break;
  38.835 +                        }
  38.836 +                    }
  38.837 +                    compiledPattern.append((char)(TAG_QUOTE_CHARS << 8 | (j - i)));
  38.838 +                    for (; i < j; i++) {
  38.839 +                        compiledPattern.append(pattern.charAt(i));
  38.840 +                    }
  38.841 +                    i--;
  38.842 +                }
  38.843 +                continue;
  38.844 +            }
  38.845 +
  38.846 +            int tag;
  38.847 +            if ((tag = DateFormatSymbols.patternChars.indexOf(c)) == -1) {
  38.848 +                throw new IllegalArgumentException("Illegal pattern character " +
  38.849 +                                                   "'" + c + "'");
  38.850 +            }
  38.851 +            if (lastTag == -1 || lastTag == tag) {
  38.852 +                lastTag = tag;
  38.853 +                count++;
  38.854 +                continue;
  38.855 +            }
  38.856 +            encode(lastTag, count, compiledPattern);
  38.857 +            lastTag = tag;
  38.858 +            count = 1;
  38.859 +        }
  38.860 +
  38.861 +        if (inQuote) {
  38.862 +            throw new IllegalArgumentException("Unterminated quote");
  38.863 +        }
  38.864 +
  38.865 +        if (count != 0) {
  38.866 +            encode(lastTag, count, compiledPattern);
  38.867 +        }
  38.868 +
  38.869 +        // Copy the compiled pattern to a char array
  38.870 +        int len = compiledPattern.length();
  38.871 +        char[] r = new char[len];
  38.872 +        compiledPattern.getChars(0, len, r, 0);
  38.873 +        return r;
  38.874 +    }
  38.875 +
  38.876 +    /**
  38.877 +     * Encodes the given tag and length and puts encoded char(s) into buffer.
  38.878 +     */
  38.879 +    private static final void encode(int tag, int length, StringBuilder buffer) {
  38.880 +        if (tag == PATTERN_ISO_ZONE && length >= 4) {
  38.881 +            throw new IllegalArgumentException("invalid ISO 8601 format: length=" + length);
  38.882 +        }
  38.883 +        if (length < 255) {
  38.884 +            buffer.append((char)(tag << 8 | length));
  38.885 +        } else {
  38.886 +            buffer.append((char)((tag << 8) | 0xff));
  38.887 +            buffer.append((char)(length >>> 16));
  38.888 +            buffer.append((char)(length & 0xffff));
  38.889 +        }
  38.890 +    }
  38.891 +
  38.892 +    /* Initialize the fields we use to disambiguate ambiguous years. Separate
  38.893 +     * so we can call it from readObject().
  38.894 +     */
  38.895 +    private void initializeDefaultCentury() {
  38.896 +        calendar.setTimeInMillis(System.currentTimeMillis());
  38.897 +        calendar.add( Calendar.YEAR, -80 );
  38.898 +        parseAmbiguousDatesAsAfter(calendar.getTime());
  38.899 +    }
  38.900 +
  38.901 +    /* Define one-century window into which to disambiguate dates using
  38.902 +     * two-digit years.
  38.903 +     */
  38.904 +    private void parseAmbiguousDatesAsAfter(Date startDate) {
  38.905 +        defaultCenturyStart = startDate;
  38.906 +        calendar.setTime(startDate);
  38.907 +        defaultCenturyStartYear = calendar.get(Calendar.YEAR);
  38.908 +    }
  38.909 +
  38.910 +    /**
  38.911 +     * Sets the 100-year period 2-digit years will be interpreted as being in
  38.912 +     * to begin on the date the user specifies.
  38.913 +     *
  38.914 +     * @param startDate During parsing, two digit years will be placed in the range
  38.915 +     * <code>startDate</code> to <code>startDate + 100 years</code>.
  38.916 +     * @see #get2DigitYearStart
  38.917 +     * @since 1.2
  38.918 +     */
  38.919 +    public void set2DigitYearStart(Date startDate) {
  38.920 +        parseAmbiguousDatesAsAfter(new Date(startDate.getTime()));
  38.921 +    }
  38.922 +
  38.923 +    /**
  38.924 +     * Returns the beginning date of the 100-year period 2-digit years are interpreted
  38.925 +     * as being within.
  38.926 +     *
  38.927 +     * @return the start of the 100-year period into which two digit years are
  38.928 +     * parsed
  38.929 +     * @see #set2DigitYearStart
  38.930 +     * @since 1.2
  38.931 +     */
  38.932 +    public Date get2DigitYearStart() {
  38.933 +        return (Date) defaultCenturyStart.clone();
  38.934 +    }
  38.935 +
  38.936 +    /**
  38.937 +     * Formats the given <code>Date</code> into a date/time string and appends
  38.938 +     * the result to the given <code>StringBuffer</code>.
  38.939 +     *
  38.940 +     * @param date the date-time value to be formatted into a date-time string.
  38.941 +     * @param toAppendTo where the new date-time text is to be appended.
  38.942 +     * @param pos the formatting position. On input: an alignment field,
  38.943 +     * if desired. On output: the offsets of the alignment field.
  38.944 +     * @return the formatted date-time string.
  38.945 +     * @exception NullPointerException if the given {@code date} is {@code null}.
  38.946 +     */
  38.947 +    public StringBuffer format(Date date, StringBuffer toAppendTo,
  38.948 +                               FieldPosition pos)
  38.949 +    {
  38.950 +        pos.beginIndex = pos.endIndex = 0;
  38.951 +        return format(date, toAppendTo, pos.getFieldDelegate());
  38.952 +    }
  38.953 +
  38.954 +    // Called from Format after creating a FieldDelegate
  38.955 +    private StringBuffer format(Date date, StringBuffer toAppendTo,
  38.956 +                                FieldDelegate delegate) {
  38.957 +        // Convert input date to time field list
  38.958 +        calendar.setTime(date);
  38.959 +
  38.960 +        boolean useDateFormatSymbols = useDateFormatSymbols();
  38.961 +
  38.962 +        for (int i = 0; i < compiledPattern.length; ) {
  38.963 +            int tag = compiledPattern[i] >>> 8;
  38.964 +            int count = compiledPattern[i++] & 0xff;
  38.965 +            if (count == 255) {
  38.966 +                count = compiledPattern[i++] << 16;
  38.967 +                count |= compiledPattern[i++];
  38.968 +            }
  38.969 +
  38.970 +            switch (tag) {
  38.971 +            case TAG_QUOTE_ASCII_CHAR:
  38.972 +                toAppendTo.append((char)count);
  38.973 +                break;
  38.974 +
  38.975 +            case TAG_QUOTE_CHARS:
  38.976 +                toAppendTo.append(compiledPattern, i, count);
  38.977 +                i += count;
  38.978 +                break;
  38.979 +
  38.980 +            default:
  38.981 +                subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
  38.982 +                break;
  38.983 +            }
  38.984 +        }
  38.985 +        return toAppendTo;
  38.986 +    }
  38.987 +
  38.988 +    /**
  38.989 +     * Formats an Object producing an <code>AttributedCharacterIterator</code>.
  38.990 +     * You can use the returned <code>AttributedCharacterIterator</code>
  38.991 +     * to build the resulting String, as well as to determine information
  38.992 +     * about the resulting String.
  38.993 +     * <p>
  38.994 +     * Each attribute key of the AttributedCharacterIterator will be of type
  38.995 +     * <code>DateFormat.Field</code>, with the corresponding attribute value
  38.996 +     * being the same as the attribute key.
  38.997 +     *
  38.998 +     * @exception NullPointerException if obj is null.
  38.999 +     * @exception IllegalArgumentException if the Format cannot format the
 38.1000 +     *            given object, or if the Format's pattern string is invalid.
 38.1001 +     * @param obj The object to format
 38.1002 +     * @return AttributedCharacterIterator describing the formatted value.
 38.1003 +     * @since 1.4
 38.1004 +     */
 38.1005 +    public AttributedCharacterIterator formatToCharacterIterator(Object obj) {
 38.1006 +        StringBuffer sb = new StringBuffer();
 38.1007 +        CharacterIteratorFieldDelegate delegate = new
 38.1008 +                         CharacterIteratorFieldDelegate();
 38.1009 +
 38.1010 +        if (obj instanceof Date) {
 38.1011 +            format((Date)obj, sb, delegate);
 38.1012 +        }
 38.1013 +        else if (obj instanceof Number) {
 38.1014 +            format(new Date(((Number)obj).longValue()), sb, delegate);
 38.1015 +        }
 38.1016 +        else if (obj == null) {
 38.1017 +            throw new NullPointerException(
 38.1018 +                   "formatToCharacterIterator must be passed non-null object");
 38.1019 +        }
 38.1020 +        else {
 38.1021 +            throw new IllegalArgumentException(
 38.1022 +                             "Cannot format given Object as a Date");
 38.1023 +        }
 38.1024 +        return delegate.getIterator(sb.toString());
 38.1025 +    }
 38.1026 +
 38.1027 +    // Map index into pattern character string to Calendar field number
 38.1028 +    private static final int[] PATTERN_INDEX_TO_CALENDAR_FIELD =
 38.1029 +    {
 38.1030 +        Calendar.ERA, Calendar.YEAR, Calendar.MONTH, Calendar.DATE,
 38.1031 +        Calendar.HOUR_OF_DAY, Calendar.HOUR_OF_DAY, Calendar.MINUTE,
 38.1032 +        Calendar.SECOND, Calendar.MILLISECOND, Calendar.DAY_OF_WEEK,
 38.1033 +        Calendar.DAY_OF_YEAR, Calendar.DAY_OF_WEEK_IN_MONTH,
 38.1034 +        Calendar.WEEK_OF_YEAR, Calendar.WEEK_OF_MONTH,
 38.1035 +        Calendar.AM_PM, Calendar.HOUR, Calendar.HOUR, Calendar.ZONE_OFFSET,
 38.1036 +        Calendar.ZONE_OFFSET,
 38.1037 +        // Pseudo Calendar fields
 38.1038 +        CalendarBuilder.WEEK_YEAR,
 38.1039 +        CalendarBuilder.ISO_DAY_OF_WEEK,
 38.1040 +        Calendar.ZONE_OFFSET
 38.1041 +    };
 38.1042 +
 38.1043 +    // Map index into pattern character string to DateFormat field number
 38.1044 +    private static final int[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD = {
 38.1045 +        DateFormat.ERA_FIELD, DateFormat.YEAR_FIELD, DateFormat.MONTH_FIELD,
 38.1046 +        DateFormat.DATE_FIELD, DateFormat.HOUR_OF_DAY1_FIELD,
 38.1047 +        DateFormat.HOUR_OF_DAY0_FIELD, DateFormat.MINUTE_FIELD,
 38.1048 +        DateFormat.SECOND_FIELD, DateFormat.MILLISECOND_FIELD,
 38.1049 +        DateFormat.DAY_OF_WEEK_FIELD, DateFormat.DAY_OF_YEAR_FIELD,
 38.1050 +        DateFormat.DAY_OF_WEEK_IN_MONTH_FIELD, DateFormat.WEEK_OF_YEAR_FIELD,
 38.1051 +        DateFormat.WEEK_OF_MONTH_FIELD, DateFormat.AM_PM_FIELD,
 38.1052 +        DateFormat.HOUR1_FIELD, DateFormat.HOUR0_FIELD,
 38.1053 +        DateFormat.TIMEZONE_FIELD, DateFormat.TIMEZONE_FIELD,
 38.1054 +        DateFormat.YEAR_FIELD, DateFormat.DAY_OF_WEEK_FIELD,
 38.1055 +        DateFormat.TIMEZONE_FIELD
 38.1056 +    };
 38.1057 +
 38.1058 +    // Maps from DecimalFormatSymbols index to Field constant
 38.1059 +    private static final Field[] PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID = {
 38.1060 +        Field.ERA, Field.YEAR, Field.MONTH, Field.DAY_OF_MONTH,
 38.1061 +        Field.HOUR_OF_DAY1, Field.HOUR_OF_DAY0, Field.MINUTE,
 38.1062 +        Field.SECOND, Field.MILLISECOND, Field.DAY_OF_WEEK,
 38.1063 +        Field.DAY_OF_YEAR, Field.DAY_OF_WEEK_IN_MONTH,
 38.1064 +        Field.WEEK_OF_YEAR, Field.WEEK_OF_MONTH,
 38.1065 +        Field.AM_PM, Field.HOUR1, Field.HOUR0, Field.TIME_ZONE,
 38.1066 +        Field.TIME_ZONE,
 38.1067 +        Field.YEAR, Field.DAY_OF_WEEK,
 38.1068 +        Field.TIME_ZONE
 38.1069 +    };
 38.1070 +
 38.1071 +    /**
 38.1072 +     * Private member function that does the real date/time formatting.
 38.1073 +     */
 38.1074 +    private void subFormat(int patternCharIndex, int count,
 38.1075 +                           FieldDelegate delegate, StringBuffer buffer,
 38.1076 +                           boolean useDateFormatSymbols)
 38.1077 +    {
 38.1078 +        int     maxIntCount = Integer.MAX_VALUE;
 38.1079 +        String  current = null;
 38.1080 +        int     beginOffset = buffer.length();
 38.1081 +
 38.1082 +        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
 38.1083 +        int value;
 38.1084 +        if (field == CalendarBuilder.WEEK_YEAR) {
 38.1085 +            if (calendar.isWeekDateSupported()) {
 38.1086 +                value = calendar.getWeekYear();
 38.1087 +            } else {
 38.1088 +                // use calendar year 'y' instead
 38.1089 +                patternCharIndex = PATTERN_YEAR;
 38.1090 +                field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
 38.1091 +                value = calendar.get(field);
 38.1092 +            }
 38.1093 +        } else if (field == CalendarBuilder.ISO_DAY_OF_WEEK) {
 38.1094 +            value = CalendarBuilder.toISODayOfWeek(calendar.get(Calendar.DAY_OF_WEEK));
 38.1095 +        } else {
 38.1096 +            value = calendar.get(field);
 38.1097 +        }
 38.1098 +
 38.1099 +        int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
 38.1100 +        if (!useDateFormatSymbols && field != CalendarBuilder.ISO_DAY_OF_WEEK) {
 38.1101 +            current = calendar.getDisplayName(field, style, locale);
 38.1102 +        }
 38.1103 +
 38.1104 +        // Note: zeroPaddingNumber() assumes that maxDigits is either
 38.1105 +        // 2 or maxIntCount. If we make any changes to this,
 38.1106 +        // zeroPaddingNumber() must be fixed.
 38.1107 +
 38.1108 +        switch (patternCharIndex) {
 38.1109 +        case PATTERN_ERA: // 'G'
 38.1110 +            if (useDateFormatSymbols) {
 38.1111 +                String[] eras = formatData.getEras();
 38.1112 +                if (value < eras.length)
 38.1113 +                    current = eras[value];
 38.1114 +            }
 38.1115 +            if (current == null)
 38.1116 +                current = "";
 38.1117 +            break;
 38.1118 +
 38.1119 +        case PATTERN_WEEK_YEAR: // 'Y'
 38.1120 +        case PATTERN_YEAR:      // 'y'
 38.1121 +            if (calendar instanceof GregorianCalendar) {
 38.1122 +                if (count != 2)
 38.1123 +                    zeroPaddingNumber(value, count, maxIntCount, buffer);
 38.1124 +                else // count == 2
 38.1125 +                    zeroPaddingNumber(value, 2, 2, buffer); // clip 1996 to 96
 38.1126 +            } else {
 38.1127 +                if (current == null) {
 38.1128 +                    zeroPaddingNumber(value, style == Calendar.LONG ? 1 : count,
 38.1129 +                                      maxIntCount, buffer);
 38.1130 +                }
 38.1131 +            }
 38.1132 +            break;
 38.1133 +
 38.1134 +        case PATTERN_MONTH: // 'M'
 38.1135 +            if (useDateFormatSymbols) {
 38.1136 +                String[] months;
 38.1137 +                if (count >= 4) {
 38.1138 +                    months = formatData.getMonths();
 38.1139 +                    current = months[value];
 38.1140 +                } else if (count == 3) {
 38.1141 +                    months = formatData.getShortMonths();
 38.1142 +                    current = months[value];
 38.1143 +                }
 38.1144 +            } else {
 38.1145 +                if (count < 3) {
 38.1146 +                    current = null;
 38.1147 +                }
 38.1148 +            }
 38.1149 +            if (current == null) {
 38.1150 +                zeroPaddingNumber(value+1, count, maxIntCount, buffer);
 38.1151 +            }
 38.1152 +            break;
 38.1153 +
 38.1154 +        case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
 38.1155 +            if (current == null) {
 38.1156 +                if (value == 0)
 38.1157 +                    zeroPaddingNumber(calendar.getMaximum(Calendar.HOUR_OF_DAY)+1,
 38.1158 +                                      count, maxIntCount, buffer);
 38.1159 +                else
 38.1160 +                    zeroPaddingNumber(value, count, maxIntCount, buffer);
 38.1161 +            }
 38.1162 +            break;
 38.1163 +
 38.1164 +        case PATTERN_DAY_OF_WEEK: // 'E'
 38.1165 +            if (useDateFormatSymbols) {
 38.1166 +                String[] weekdays;
 38.1167 +                if (count >= 4) {
 38.1168 +                    weekdays = formatData.getWeekdays();
 38.1169 +                    current = weekdays[value];
 38.1170 +                } else { // count < 4, use abbreviated form if exists
 38.1171 +                    weekdays = formatData.getShortWeekdays();
 38.1172 +                    current = weekdays[value];
 38.1173 +                }
 38.1174 +            }
 38.1175 +            break;
 38.1176 +
 38.1177 +        case PATTERN_AM_PM:    // 'a'
 38.1178 +            if (useDateFormatSymbols) {
 38.1179 +                String[] ampm = formatData.getAmPmStrings();
 38.1180 +                current = ampm[value];
 38.1181 +            }
 38.1182 +            break;
 38.1183 +
 38.1184 +        case PATTERN_HOUR1:    // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
 38.1185 +            if (current == null) {
 38.1186 +                if (value == 0)
 38.1187 +                    zeroPaddingNumber(calendar.getLeastMaximum(Calendar.HOUR)+1,
 38.1188 +                                      count, maxIntCount, buffer);
 38.1189 +                else
 38.1190 +                    zeroPaddingNumber(value, count, maxIntCount, buffer);
 38.1191 +            }
 38.1192 +            break;
 38.1193 +
 38.1194 +        case PATTERN_ZONE_NAME: // 'z'
 38.1195 +            if (current == null) {
 38.1196 +                if (formatData.locale == null || formatData.isZoneStringsSet) {
 38.1197 +                    int zoneIndex =
 38.1198 +                        formatData.getZoneIndex(calendar.getTimeZone().getID());
 38.1199 +                    if (zoneIndex == -1) {
 38.1200 +                        value = calendar.get(Calendar.ZONE_OFFSET) +
 38.1201 +                            calendar.get(Calendar.DST_OFFSET);
 38.1202 +                        buffer.append(ZoneInfoFile.toCustomID(value));
 38.1203 +                    } else {
 38.1204 +                        int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
 38.1205 +                        if (count < 4) {
 38.1206 +                            // Use the short name
 38.1207 +                            index++;
 38.1208 +                        }
 38.1209 +                        String[][] zoneStrings = formatData.getZoneStringsWrapper();
 38.1210 +                        buffer.append(zoneStrings[zoneIndex][index]);
 38.1211 +                    }
 38.1212 +                } else {
 38.1213 +                    TimeZone tz = calendar.getTimeZone();
 38.1214 +                    boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
 38.1215 +                    int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
 38.1216 +                    buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
 38.1217 +                }
 38.1218 +            }
 38.1219 +            break;
 38.1220 +
 38.1221 +        case PATTERN_ZONE_VALUE: // 'Z' ("-/+hhmm" form)
 38.1222 +            value = (calendar.get(Calendar.ZONE_OFFSET) +
 38.1223 +                     calendar.get(Calendar.DST_OFFSET)) / 60000;
 38.1224 +
 38.1225 +            int width = 4;
 38.1226 +            if (value >= 0) {
 38.1227 +                buffer.append('+');
 38.1228 +            } else {
 38.1229 +                width++;
 38.1230 +            }
 38.1231 +
 38.1232 +            int num = (value / 60) * 100 + (value % 60);
 38.1233 +            CalendarUtils.sprintf0d(buffer, num, width);
 38.1234 +            break;
 38.1235 +
 38.1236 +        case PATTERN_ISO_ZONE:   // 'X'
 38.1237 +            value = calendar.get(Calendar.ZONE_OFFSET)
 38.1238 +                    + calendar.get(Calendar.DST_OFFSET);
 38.1239 +
 38.1240 +            if (value == 0) {
 38.1241 +                buffer.append('Z');
 38.1242 +                break;
 38.1243 +            }
 38.1244 +
 38.1245 +            value /=  60000;
 38.1246 +            if (value >= 0) {
 38.1247 +                buffer.append('+');
 38.1248 +            } else {
 38.1249 +                buffer.append('-');
 38.1250 +                value = -value;
 38.1251 +            }
 38.1252 +
 38.1253 +            CalendarUtils.sprintf0d(buffer, value / 60, 2);
 38.1254 +            if (count == 1) {
 38.1255 +                break;
 38.1256 +            }
 38.1257 +
 38.1258 +            if (count == 3) {
 38.1259 +                buffer.append(':');
 38.1260 +            }
 38.1261 +            CalendarUtils.sprintf0d(buffer, value % 60, 2);
 38.1262 +            break;
 38.1263 +
 38.1264 +        default:
 38.1265 +     // case PATTERN_DAY_OF_MONTH:         // 'd'
 38.1266 +     // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
 38.1267 +     // case PATTERN_MINUTE:               // 'm'
 38.1268 +     // case PATTERN_SECOND:               // 's'
 38.1269 +     // case PATTERN_MILLISECOND:          // 'S'
 38.1270 +     // case PATTERN_DAY_OF_YEAR:          // 'D'
 38.1271 +     // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
 38.1272 +     // case PATTERN_WEEK_OF_YEAR:         // 'w'
 38.1273 +     // case PATTERN_WEEK_OF_MONTH:        // 'W'
 38.1274 +     // case PATTERN_HOUR0:                // 'K' eg, 11PM + 1 hour =>> 0 AM
 38.1275 +     // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' pseudo field, Monday = 1, ..., Sunday = 7
 38.1276 +            if (current == null) {
 38.1277 +                zeroPaddingNumber(value, count, maxIntCount, buffer);
 38.1278 +            }
 38.1279 +            break;
 38.1280 +        } // switch (patternCharIndex)
 38.1281 +
 38.1282 +        if (current != null) {
 38.1283 +            buffer.append(current);
 38.1284 +        }
 38.1285 +
 38.1286 +        int fieldID = PATTERN_INDEX_TO_DATE_FORMAT_FIELD[patternCharIndex];
 38.1287 +        Field f = PATTERN_INDEX_TO_DATE_FORMAT_FIELD_ID[patternCharIndex];
 38.1288 +
 38.1289 +        delegate.formatted(fieldID, f, f, beginOffset, buffer.length(), buffer);
 38.1290 +    }
 38.1291 +
 38.1292 +    /**
 38.1293 +     * Formats a number with the specified minimum and maximum number of digits.
 38.1294 +     */
 38.1295 +    private final void zeroPaddingNumber(int value, int minDigits, int maxDigits, StringBuffer buffer)
 38.1296 +    {
 38.1297 +        // Optimization for 1, 2 and 4 digit numbers. This should
 38.1298 +        // cover most cases of formatting date/time related items.
 38.1299 +        // Note: This optimization code assumes that maxDigits is
 38.1300 +        // either 2 or Integer.MAX_VALUE (maxIntCount in format()).
 38.1301 +        try {
 38.1302 +            if (zeroDigit == 0) {
 38.1303 +                zeroDigit = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getZeroDigit();
 38.1304 +            }
 38.1305 +            if (value >= 0) {
 38.1306 +                if (value < 100 && minDigits >= 1 && minDigits <= 2) {
 38.1307 +                    if (value < 10) {
 38.1308 +                        if (minDigits == 2) {
 38.1309 +                            buffer.append(zeroDigit);
 38.1310 +                        }
 38.1311 +                        buffer.append((char)(zeroDigit + value));
 38.1312 +                    } else {
 38.1313 +                        buffer.append((char)(zeroDigit + value / 10));
 38.1314 +                        buffer.append((char)(zeroDigit + value % 10));
 38.1315 +                    }
 38.1316 +                    return;
 38.1317 +                } else if (value >= 1000 && value < 10000) {
 38.1318 +                    if (minDigits == 4) {
 38.1319 +                        buffer.append((char)(zeroDigit + value / 1000));
 38.1320 +                        value %= 1000;
 38.1321 +                        buffer.append((char)(zeroDigit + value / 100));
 38.1322 +                        value %= 100;
 38.1323 +                        buffer.append((char)(zeroDigit + value / 10));
 38.1324 +                        buffer.append((char)(zeroDigit + value % 10));
 38.1325 +                        return;
 38.1326 +                    }
 38.1327 +                    if (minDigits == 2 && maxDigits == 2) {
 38.1328 +                        zeroPaddingNumber(value % 100, 2, 2, buffer);
 38.1329 +                        return;
 38.1330 +                    }
 38.1331 +                }
 38.1332 +            }
 38.1333 +        } catch (Exception e) {
 38.1334 +        }
 38.1335 +
 38.1336 +        numberFormat.setMinimumIntegerDigits(minDigits);
 38.1337 +        numberFormat.setMaximumIntegerDigits(maxDigits);
 38.1338 +        numberFormat.format((long)value, buffer, DontCareFieldPosition.INSTANCE);
 38.1339 +    }
 38.1340 +
 38.1341 +
 38.1342 +    /**
 38.1343 +     * Parses text from a string to produce a <code>Date</code>.
 38.1344 +     * <p>
 38.1345 +     * The method attempts to parse text starting at the index given by
 38.1346 +     * <code>pos</code>.
 38.1347 +     * If parsing succeeds, then the index of <code>pos</code> is updated
 38.1348 +     * to the index after the last character used (parsing does not necessarily
 38.1349 +     * use all characters up to the end of the string), and the parsed
 38.1350 +     * date is returned. The updated <code>pos</code> can be used to
 38.1351 +     * indicate the starting point for the next call to this method.
 38.1352 +     * If an error occurs, then the index of <code>pos</code> is not
 38.1353 +     * changed, the error index of <code>pos</code> is set to the index of
 38.1354 +     * the character where the error occurred, and null is returned.
 38.1355 +     *
 38.1356 +     * <p>This parsing operation uses the {@link DateFormat#calendar
 38.1357 +     * calendar} to produce a {@code Date}. All of the {@code
 38.1358 +     * calendar}'s date-time fields are {@linkplain Calendar#clear()
 38.1359 +     * cleared} before parsing, and the {@code calendar}'s default
 38.1360 +     * values of the date-time fields are used for any missing
 38.1361 +     * date-time information. For example, the year value of the
 38.1362 +     * parsed {@code Date} is 1970 with {@link GregorianCalendar} if
 38.1363 +     * no year value is given from the parsing operation.  The {@code
 38.1364 +     * TimeZone} value may be overwritten, depending on the given
 38.1365 +     * pattern and the time zone value in {@code text}. Any {@code
 38.1366 +     * TimeZone} value that has previously been set by a call to
 38.1367 +     * {@link #setTimeZone(java.util.TimeZone) setTimeZone} may need
 38.1368 +     * to be restored for further operations.
 38.1369 +     *
 38.1370 +     * @param text  A <code>String</code>, part of which should be parsed.
 38.1371 +     * @param pos   A <code>ParsePosition</code> object with index and error
 38.1372 +     *              index information as described above.
 38.1373 +     * @return A <code>Date</code> parsed from the string. In case of
 38.1374 +     *         error, returns null.
 38.1375 +     * @exception NullPointerException if <code>text</code> or <code>pos</code> is null.
 38.1376 +     */
 38.1377 +    public Date parse(String text, ParsePosition pos)
 38.1378 +    {
 38.1379 +        checkNegativeNumberExpression();
 38.1380 +
 38.1381 +        int start = pos.index;
 38.1382 +        int oldStart = start;
 38.1383 +        int textLength = text.length();
 38.1384 +
 38.1385 +        boolean[] ambiguousYear = {false};
 38.1386 +
 38.1387 +        CalendarBuilder calb = new CalendarBuilder();
 38.1388 +
 38.1389 +        for (int i = 0; i < compiledPattern.length; ) {
 38.1390 +            int tag = compiledPattern[i] >>> 8;
 38.1391 +            int count = compiledPattern[i++] & 0xff;
 38.1392 +            if (count == 255) {
 38.1393 +                count = compiledPattern[i++] << 16;
 38.1394 +                count |= compiledPattern[i++];
 38.1395 +            }
 38.1396 +
 38.1397 +            switch (tag) {
 38.1398 +            case TAG_QUOTE_ASCII_CHAR:
 38.1399 +                if (start >= textLength || text.charAt(start) != (char)count) {
 38.1400 +                    pos.index = oldStart;
 38.1401 +                    pos.errorIndex = start;
 38.1402 +                    return null;
 38.1403 +                }
 38.1404 +                start++;
 38.1405 +                break;
 38.1406 +
 38.1407 +            case TAG_QUOTE_CHARS:
 38.1408 +                while (count-- > 0) {
 38.1409 +                    if (start >= textLength || text.charAt(start) != compiledPattern[i++]) {
 38.1410 +                        pos.index = oldStart;
 38.1411 +                        pos.errorIndex = start;
 38.1412 +                        return null;
 38.1413 +                    }
 38.1414 +                    start++;
 38.1415 +                }
 38.1416 +                break;
 38.1417 +
 38.1418 +            default:
 38.1419 +                // Peek the next pattern to determine if we need to
 38.1420 +                // obey the number of pattern letters for
 38.1421 +                // parsing. It's required when parsing contiguous
 38.1422 +                // digit text (e.g., "20010704") with a pattern which
 38.1423 +                // has no delimiters between fields, like "yyyyMMdd".
 38.1424 +                boolean obeyCount = false;
 38.1425 +
 38.1426 +                // In Arabic, a minus sign for a negative number is put after
 38.1427 +                // the number. Even in another locale, a minus sign can be
 38.1428 +                // put after a number using DateFormat.setNumberFormat().
 38.1429 +                // If both the minus sign and the field-delimiter are '-',
 38.1430 +                // subParse() needs to determine whether a '-' after a number
 38.1431 +                // in the given text is a delimiter or is a minus sign for the
 38.1432 +                // preceding number. We give subParse() a clue based on the
 38.1433 +                // information in compiledPattern.
 38.1434 +                boolean useFollowingMinusSignAsDelimiter = false;
 38.1435 +
 38.1436 +                if (i < compiledPattern.length) {
 38.1437 +                    int nextTag = compiledPattern[i] >>> 8;
 38.1438 +                    if (!(nextTag == TAG_QUOTE_ASCII_CHAR ||
 38.1439 +                          nextTag == TAG_QUOTE_CHARS)) {
 38.1440 +                        obeyCount = true;
 38.1441 +                    }
 38.1442 +
 38.1443 +                    if (hasFollowingMinusSign &&
 38.1444 +                        (nextTag == TAG_QUOTE_ASCII_CHAR ||
 38.1445 +                         nextTag == TAG_QUOTE_CHARS)) {
 38.1446 +                        int c;
 38.1447 +                        if (nextTag == TAG_QUOTE_ASCII_CHAR) {
 38.1448 +                            c = compiledPattern[i] & 0xff;
 38.1449 +                        } else {
 38.1450 +                            c = compiledPattern[i+1];
 38.1451 +                        }
 38.1452 +
 38.1453 +                        if (c == minusSign) {
 38.1454 +                            useFollowingMinusSignAsDelimiter = true;
 38.1455 +                        }
 38.1456 +                    }
 38.1457 +                }
 38.1458 +                start = subParse(text, start, tag, count, obeyCount,
 38.1459 +                                 ambiguousYear, pos,
 38.1460 +                                 useFollowingMinusSignAsDelimiter, calb);
 38.1461 +                if (start < 0) {
 38.1462 +                    pos.index = oldStart;
 38.1463 +                    return null;
 38.1464 +                }
 38.1465 +            }
 38.1466 +        }
 38.1467 +
 38.1468 +        // At this point the fields of Calendar have been set.  Calendar
 38.1469 +        // will fill in default values for missing fields when the time
 38.1470 +        // is computed.
 38.1471 +
 38.1472 +        pos.index = start;
 38.1473 +
 38.1474 +        Date parsedDate;
 38.1475 +        try {
 38.1476 +            parsedDate = calb.establish(calendar).getTime();
 38.1477 +            // If the year value is ambiguous,
 38.1478 +            // then the two-digit year == the default start year
 38.1479 +            if (ambiguousYear[0]) {
 38.1480 +                if (parsedDate.before(defaultCenturyStart)) {
 38.1481 +                    parsedDate = calb.addYear(100).establish(calendar).getTime();
 38.1482 +                }
 38.1483 +            }
 38.1484 +        }
 38.1485 +        // An IllegalArgumentException will be thrown by Calendar.getTime()
 38.1486 +        // if any fields are out of range, e.g., MONTH == 17.
 38.1487 +        catch (IllegalArgumentException e) {
 38.1488 +            pos.errorIndex = start;
 38.1489 +            pos.index = oldStart;
 38.1490 +            return null;
 38.1491 +        }
 38.1492 +
 38.1493 +        return parsedDate;
 38.1494 +    }
 38.1495 +
 38.1496 +    /**
 38.1497 +     * Private code-size reduction function used by subParse.
 38.1498 +     * @param text the time text being parsed.
 38.1499 +     * @param start where to start parsing.
 38.1500 +     * @param field the date field being parsed.
 38.1501 +     * @param data the string array to parsed.
 38.1502 +     * @return the new start position if matching succeeded; a negative number
 38.1503 +     * indicating matching failure, otherwise.
 38.1504 +     */
 38.1505 +    private int matchString(String text, int start, int field, String[] data, CalendarBuilder calb)
 38.1506 +    {
 38.1507 +        int i = 0;
 38.1508 +        int count = data.length;
 38.1509 +
 38.1510 +        if (field == Calendar.DAY_OF_WEEK) i = 1;
 38.1511 +
 38.1512 +        // There may be multiple strings in the data[] array which begin with
 38.1513 +        // the same prefix (e.g., Cerven and Cervenec (June and July) in Czech).
 38.1514 +        // We keep track of the longest match, and return that.  Note that this
 38.1515 +        // unfortunately requires us to test all array elements.
 38.1516 +        int bestMatchLength = 0, bestMatch = -1;
 38.1517 +        for (; i<count; ++i)
 38.1518 +        {
 38.1519 +            int length = data[i].length();
 38.1520 +            // Always compare if we have no match yet; otherwise only compare
 38.1521 +            // against potentially better matches (longer strings).
 38.1522 +            if (length > bestMatchLength &&
 38.1523 +                text.regionMatches(true, start, data[i], 0, length))
 38.1524 +            {
 38.1525 +                bestMatch = i;
 38.1526 +                bestMatchLength = length;
 38.1527 +            }
 38.1528 +        }
 38.1529 +        if (bestMatch >= 0)
 38.1530 +        {
 38.1531 +            calb.set(field, bestMatch);
 38.1532 +            return start + bestMatchLength;
 38.1533 +        }
 38.1534 +        return -start;
 38.1535 +    }
 38.1536 +
 38.1537 +    /**
 38.1538 +     * Performs the same thing as matchString(String, int, int,
 38.1539 +     * String[]). This method takes a Map<String, Integer> instead of
 38.1540 +     * String[].
 38.1541 +     */
 38.1542 +    private int matchString(String text, int start, int field,
 38.1543 +                            Map<String,Integer> data, CalendarBuilder calb) {
 38.1544 +        if (data != null) {
 38.1545 +            String bestMatch = null;
 38.1546 +
 38.1547 +            for (String name : data.keySet()) {
 38.1548 +                int length = name.length();
 38.1549 +                if (bestMatch == null || length > bestMatch.length()) {
 38.1550 +                    if (text.regionMatches(true, start, name, 0, length)) {
 38.1551 +                        bestMatch = name;
 38.1552 +                    }
 38.1553 +                }
 38.1554 +            }
 38.1555 +
 38.1556 +            if (bestMatch != null) {
 38.1557 +                calb.set(field, data.get(bestMatch));
 38.1558 +                return start + bestMatch.length();
 38.1559 +            }
 38.1560 +        }
 38.1561 +        return -start;
 38.1562 +    }
 38.1563 +
 38.1564 +    private int matchZoneString(String text, int start, String[] zoneNames) {
 38.1565 +        for (int i = 1; i <= 4; ++i) {
 38.1566 +            // Checking long and short zones [1 & 2],
 38.1567 +            // and long and short daylight [3 & 4].
 38.1568 +            String zoneName = zoneNames[i];
 38.1569 +            if (text.regionMatches(true, start,
 38.1570 +                                   zoneName, 0, zoneName.length())) {
 38.1571 +                return i;
 38.1572 +            }
 38.1573 +        }
 38.1574 +        return -1;
 38.1575 +    }
 38.1576 +
 38.1577 +    private boolean matchDSTString(String text, int start, int zoneIndex, int standardIndex,
 38.1578 +                                   String[][] zoneStrings) {
 38.1579 +        int index = standardIndex + 2;
 38.1580 +        String zoneName  = zoneStrings[zoneIndex][index];
 38.1581 +        if (text.regionMatches(true, start,
 38.1582 +                               zoneName, 0, zoneName.length())) {
 38.1583 +            return true;
 38.1584 +        }
 38.1585 +        return false;
 38.1586 +    }
 38.1587 +
 38.1588 +    /**
 38.1589 +     * find time zone 'text' matched zoneStrings and set to internal
 38.1590 +     * calendar.
 38.1591 +     */
 38.1592 +    private int subParseZoneString(String text, int start, CalendarBuilder calb) {
 38.1593 +        boolean useSameName = false; // true if standard and daylight time use the same abbreviation.
 38.1594 +        TimeZone currentTimeZone = getTimeZone();
 38.1595 +
 38.1596 +        // At this point, check for named time zones by looking through
 38.1597 +        // the locale data from the TimeZoneNames strings.
 38.1598 +        // Want to be able to parse both short and long forms.
 38.1599 +        int zoneIndex = formatData.getZoneIndex(currentTimeZone.getID());
 38.1600 +        TimeZone tz = null;
 38.1601 +        String[][] zoneStrings = formatData.getZoneStringsWrapper();
 38.1602 +        String[] zoneNames = null;
 38.1603 +        int nameIndex = 0;
 38.1604 +        if (zoneIndex != -1) {
 38.1605 +            zoneNames = zoneStrings[zoneIndex];
 38.1606 +            if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
 38.1607 +                if (nameIndex <= 2) {
 38.1608 +                    // Check if the standard name (abbr) and the daylight name are the same.
 38.1609 +                    useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
 38.1610 +                }
 38.1611 +                tz = TimeZone.getTimeZone(zoneNames[0]);
 38.1612 +            }
 38.1613 +        }
 38.1614 +        if (tz == null) {
 38.1615 +            zoneIndex = formatData.getZoneIndex(TimeZone.getDefault().getID());
 38.1616 +            if (zoneIndex != -1) {
 38.1617 +                zoneNames = zoneStrings[zoneIndex];
 38.1618 +                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
 38.1619 +                    if (nameIndex <= 2) {
 38.1620 +                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
 38.1621 +                    }
 38.1622 +                    tz = TimeZone.getTimeZone(zoneNames[0]);
 38.1623 +                }
 38.1624 +            }
 38.1625 +        }
 38.1626 +
 38.1627 +        if (tz == null) {
 38.1628 +            int len = zoneStrings.length;
 38.1629 +            for (int i = 0; i < len; i++) {
 38.1630 +                zoneNames = zoneStrings[i];
 38.1631 +                if ((nameIndex = matchZoneString(text, start, zoneNames)) > 0) {
 38.1632 +                    if (nameIndex <= 2) {
 38.1633 +                        useSameName = zoneNames[nameIndex].equalsIgnoreCase(zoneNames[nameIndex + 2]);
 38.1634 +                    }
 38.1635 +                    tz = TimeZone.getTimeZone(zoneNames[0]);
 38.1636 +                    break;
 38.1637 +                }
 38.1638 +            }
 38.1639 +        }
 38.1640 +        if (tz != null) { // Matched any ?
 38.1641 +            if (!tz.equals(currentTimeZone)) {
 38.1642 +                setTimeZone(tz);
 38.1643 +            }
 38.1644 +            // If the time zone matched uses the same name
 38.1645 +            // (abbreviation) for both standard and daylight time,
 38.1646 +            // let the time zone in the Calendar decide which one.
 38.1647 +            //
 38.1648 +            // Also if tz.getDSTSaving() returns 0 for DST, use tz to
 38.1649 +            // determine the local time. (6645292)
 38.1650 +            int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0;
 38.1651 +            if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) {
 38.1652 +                calb.set(Calendar.ZONE_OFFSET, tz.getRawOffset())
 38.1653 +                    .set(Calendar.DST_OFFSET, dstAmount);
 38.1654 +            }
 38.1655 +            return (start + zoneNames[nameIndex].length());
 38.1656 +        }
 38.1657 +        return 0;
 38.1658 +    }
 38.1659 +
 38.1660 +    /**
 38.1661 +     * Parses numeric forms of time zone offset, such as "hh:mm", and
 38.1662 +     * sets calb to the parsed value.
 38.1663 +     *
 38.1664 +     * @param text  the text to be parsed
 38.1665 +     * @param start the character position to start parsing
 38.1666 +     * @param sign  1: positive; -1: negative
 38.1667 +     * @param count 0: 'Z' or "GMT+hh:mm" parsing; 1 - 3: the number of 'X's
 38.1668 +     * @param colon true - colon required between hh and mm; false - no colon required
 38.1669 +     * @param calb  a CalendarBuilder in which the parsed value is stored
 38.1670 +     * @return updated parsed position, or its negative value to indicate a parsing error
 38.1671 +     */
 38.1672 +    private int subParseNumericZone(String text, int start, int sign, int count,
 38.1673 +                                    boolean colon, CalendarBuilder calb) {
 38.1674 +        int index = start;
 38.1675 +
 38.1676 +      parse:
 38.1677 +        try {
 38.1678 +            char c = text.charAt(index++);
 38.1679 +            // Parse hh
 38.1680 +            int hours;
 38.1681 +            if (!isDigit(c)) {
 38.1682 +                break parse;
 38.1683 +            }
 38.1684 +            hours = c - '0';
 38.1685 +            c = text.charAt(index++);
 38.1686 +            if (isDigit(c)) {
 38.1687 +                hours = hours * 10 + (c - '0');
 38.1688 +            } else {
 38.1689 +                // If no colon in RFC 822 or 'X' (ISO), two digits are
 38.1690 +                // required.
 38.1691 +                if (count > 0 || !colon) {
 38.1692 +                    break parse;
 38.1693 +                }
 38.1694 +                --index;
 38.1695 +            }
 38.1696 +            if (hours > 23) {
 38.1697 +                break parse;
 38.1698 +            }
 38.1699 +            int minutes = 0;
 38.1700 +            if (count != 1) {
 38.1701 +                // Proceed with parsing mm
 38.1702 +                c = text.charAt(index++);
 38.1703 +                if (colon) {
 38.1704 +                    if (c != ':') {
 38.1705 +                        break parse;
 38.1706 +                    }
 38.1707 +                    c = text.charAt(index++);
 38.1708 +                }
 38.1709 +                if (!isDigit(c)) {
 38.1710 +                    break parse;
 38.1711 +                }
 38.1712 +                minutes = c - '0';
 38.1713 +                c = text.charAt(index++);
 38.1714 +                if (!isDigit(c)) {
 38.1715 +                    break parse;
 38.1716 +                }
 38.1717 +                minutes = minutes * 10 + (c - '0');
 38.1718 +                if (minutes > 59) {
 38.1719 +                    break parse;
 38.1720 +                }
 38.1721 +            }
 38.1722 +            minutes += hours * 60;
 38.1723 +            calb.set(Calendar.ZONE_OFFSET, minutes * MILLIS_PER_MINUTE * sign)
 38.1724 +                .set(Calendar.DST_OFFSET, 0);
 38.1725 +            return index;
 38.1726 +        } catch (IndexOutOfBoundsException e) {
 38.1727 +        }
 38.1728 +        return  1 - index; // -(index - 1)
 38.1729 +    }
 38.1730 +
 38.1731 +    private boolean isDigit(char c) {
 38.1732 +        return c >= '0' && c <= '9';
 38.1733 +    }
 38.1734 +
 38.1735 +    /**
 38.1736 +     * Private member function that converts the parsed date strings into
 38.1737 +     * timeFields. Returns -start (for ParsePosition) if failed.
 38.1738 +     * @param text the time text to be parsed.
 38.1739 +     * @param start where to start parsing.
 38.1740 +     * @param ch the pattern character for the date field text to be parsed.
 38.1741 +     * @param count the count of a pattern character.
 38.1742 +     * @param obeyCount if true, then the next field directly abuts this one,
 38.1743 +     * and we should use the count to know when to stop parsing.
 38.1744 +     * @param ambiguousYear return parameter; upon return, if ambiguousYear[0]
 38.1745 +     * is true, then a two-digit year was parsed and may need to be readjusted.
 38.1746 +     * @param origPos origPos.errorIndex is used to return an error index
 38.1747 +     * at which a parse error occurred, if matching failure occurs.
 38.1748 +     * @return the new start position if matching succeeded; -1 indicating
 38.1749 +     * matching failure, otherwise. In case matching failure occurred,
 38.1750 +     * an error index is set to origPos.errorIndex.
 38.1751 +     */
 38.1752 +    private int subParse(String text, int start, int patternCharIndex, int count,
 38.1753 +                         boolean obeyCount, boolean[] ambiguousYear,
 38.1754 +                         ParsePosition origPos,
 38.1755 +                         boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) {
 38.1756 +        Number number = null;
 38.1757 +        int value = 0;
 38.1758 +        ParsePosition pos = new ParsePosition(0);
 38.1759 +        pos.index = start;
 38.1760 +        if (patternCharIndex == PATTERN_WEEK_YEAR && !calendar.isWeekDateSupported()) {
 38.1761 +            // use calendar year 'y' instead
 38.1762 +            patternCharIndex = PATTERN_YEAR;
 38.1763 +        }
 38.1764 +        int field = PATTERN_INDEX_TO_CALENDAR_FIELD[patternCharIndex];
 38.1765 +
 38.1766 +        // If there are any spaces here, skip over them.  If we hit the end
 38.1767 +        // of the string, then fail.
 38.1768 +        for (;;) {
 38.1769 +            if (pos.index >= text.length()) {
 38.1770 +                origPos.errorIndex = start;
 38.1771 +                return -1;
 38.1772 +            }
 38.1773 +            char c = text.charAt(pos.index);
 38.1774 +            if (c != ' ' && c != '\t') break;
 38.1775 +            ++pos.index;
 38.1776 +        }
 38.1777 +
 38.1778 +      parsing:
 38.1779 +        {
 38.1780 +            // We handle a few special cases here where we need to parse
 38.1781 +            // a number value.  We handle further, more generic cases below.  We need
 38.1782 +            // to handle some of them here because some fields require extra processing on
 38.1783 +            // the parsed value.
 38.1784 +            if (patternCharIndex == PATTERN_HOUR_OF_DAY1 ||
 38.1785 +                patternCharIndex == PATTERN_HOUR1 ||
 38.1786 +                (patternCharIndex == PATTERN_MONTH && count <= 2) ||
 38.1787 +                patternCharIndex == PATTERN_YEAR ||
 38.1788 +                patternCharIndex == PATTERN_WEEK_YEAR) {
 38.1789 +                // It would be good to unify this with the obeyCount logic below,
 38.1790 +                // but that's going to be difficult.
 38.1791 +                if (obeyCount) {
 38.1792 +                    if ((start+count) > text.length()) {
 38.1793 +                        break parsing;
 38.1794 +                    }
 38.1795 +                    number = numberFormat.parse(text.substring(0, start+count), pos);
 38.1796 +                } else {
 38.1797 +                    number = numberFormat.parse(text, pos);
 38.1798 +                }
 38.1799 +                if (number == null) {
 38.1800 +                    if (patternCharIndex != PATTERN_YEAR || calendar instanceof GregorianCalendar) {
 38.1801 +                        break parsing;
 38.1802 +                    }
 38.1803 +                } else {
 38.1804 +                    value = number.intValue();
 38.1805 +
 38.1806 +                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
 38.1807 +                        (((pos.index < text.length()) &&
 38.1808 +                         (text.charAt(pos.index) != minusSign)) ||
 38.1809 +                         ((pos.index == text.length()) &&
 38.1810 +                          (text.charAt(pos.index-1) == minusSign)))) {
 38.1811 +                        value = -value;
 38.1812 +                        pos.index--;
 38.1813 +                    }
 38.1814 +                }
 38.1815 +            }
 38.1816 +
 38.1817 +            boolean useDateFormatSymbols = useDateFormatSymbols();
 38.1818 +
 38.1819 +            int index;
 38.1820 +            switch (patternCharIndex) {
 38.1821 +            case PATTERN_ERA: // 'G'
 38.1822 +                if (useDateFormatSymbols) {
 38.1823 +                    if ((index = matchString(text, start, Calendar.ERA, formatData.getEras(), calb)) > 0) {
 38.1824 +                        return index;
 38.1825 +                    }
 38.1826 +                } else {
 38.1827 +                    Map<String, Integer> map = calendar.getDisplayNames(field,
 38.1828 +                                                                        Calendar.ALL_STYLES,
 38.1829 +                                                                        locale);
 38.1830 +                    if ((index = matchString(text, start, field, map, calb)) > 0) {
 38.1831 +                        return index;
 38.1832 +                    }
 38.1833 +                }
 38.1834 +                break parsing;
 38.1835 +
 38.1836 +            case PATTERN_WEEK_YEAR: // 'Y'
 38.1837 +            case PATTERN_YEAR:      // 'y'
 38.1838 +                if (!(calendar instanceof GregorianCalendar)) {
 38.1839 +                    // calendar might have text representations for year values,
 38.1840 +                    // such as "\u5143" in JapaneseImperialCalendar.
 38.1841 +                    int style = (count >= 4) ? Calendar.LONG : Calendar.SHORT;
 38.1842 +                    Map<String, Integer> map = calendar.getDisplayNames(field, style, locale);
 38.1843 +                    if (map != null) {
 38.1844 +                        if ((index = matchString(text, start, field, map, calb)) > 0) {
 38.1845 +                            return index;
 38.1846 +                        }
 38.1847 +                    }
 38.1848 +                    calb.set(field, value);
 38.1849 +                    return pos.index;
 38.1850 +                }
 38.1851 +
 38.1852 +                // If there are 3 or more YEAR pattern characters, this indicates
 38.1853 +                // that the year value is to be treated literally, without any
 38.1854 +                // two-digit year adjustments (e.g., from "01" to 2001).  Otherwise
 38.1855 +                // we made adjustments to place the 2-digit year in the proper
 38.1856 +                // century, for parsed strings from "00" to "99".  Any other string
 38.1857 +                // is treated literally:  "2250", "-1", "1", "002".
 38.1858 +                if (count <= 2 && (pos.index - start) == 2
 38.1859 +                    && Character.isDigit(text.charAt(start))
 38.1860 +                    && Character.isDigit(text.charAt(start+1))) {
 38.1861 +                    // Assume for example that the defaultCenturyStart is 6/18/1903.
 38.1862 +                    // This means that two-digit years will be forced into the range
 38.1863 +                    // 6/18/1903 to 6/17/2003.  As a result, years 00, 01, and 02
 38.1864 +                    // correspond to 2000, 2001, and 2002.  Years 04, 05, etc. correspond
 38.1865 +                    // to 1904, 1905, etc.  If the year is 03, then it is 2003 if the
 38.1866 +                    // other fields specify a date before 6/18, or 1903 if they specify a
 38.1867 +                    // date afterwards.  As a result, 03 is an ambiguous year.  All other
 38.1868 +                    // two-digit years are unambiguous.
 38.1869 +                    int ambiguousTwoDigitYear = defaultCenturyStartYear % 100;
 38.1870 +                    ambiguousYear[0] = value == ambiguousTwoDigitYear;
 38.1871 +                    value += (defaultCenturyStartYear/100)*100 +
 38.1872 +                        (value < ambiguousTwoDigitYear ? 100 : 0);
 38.1873 +                }
 38.1874 +                calb.set(field, value);
 38.1875 +                return pos.index;
 38.1876 +
 38.1877 +            case PATTERN_MONTH: // 'M'
 38.1878 +                if (count <= 2) // i.e., M or MM.
 38.1879 +                {
 38.1880 +                    // Don't want to parse the month if it is a string
 38.1881 +                    // while pattern uses numeric style: M or MM.
 38.1882 +                    // [We computed 'value' above.]
 38.1883 +                    calb.set(Calendar.MONTH, value - 1);
 38.1884 +                    return pos.index;
 38.1885 +                }
 38.1886 +
 38.1887 +                if (useDateFormatSymbols) {
 38.1888 +                    // count >= 3 // i.e., MMM or MMMM
 38.1889 +                    // Want to be able to parse both short and long forms.
 38.1890 +                    // Try count == 4 first:
 38.1891 +                    int newStart = 0;
 38.1892 +                    if ((newStart = matchString(text, start, Calendar.MONTH,
 38.1893 +                                                formatData.getMonths(), calb)) > 0) {
 38.1894 +                        return newStart;
 38.1895 +                    }
 38.1896 +                    // count == 4 failed, now try count == 3
 38.1897 +                    if ((index = matchString(text, start, Calendar.MONTH,
 38.1898 +                                             formatData.getShortMonths(), calb)) > 0) {
 38.1899 +                        return index;
 38.1900 +                    }
 38.1901 +                } else {
 38.1902 +                    Map<String, Integer> map = calendar.getDisplayNames(field,
 38.1903 +                                                                        Calendar.ALL_STYLES,
 38.1904 +                                                                        locale);
 38.1905 +                    if ((index = matchString(text, start, field, map, calb)) > 0) {
 38.1906 +                        return index;
 38.1907 +                    }
 38.1908 +                }
 38.1909 +                break parsing;
 38.1910 +
 38.1911 +            case PATTERN_HOUR_OF_DAY1: // 'k' 1-based.  eg, 23:59 + 1 hour =>> 24:59
 38.1912 +                if (!isLenient()) {
 38.1913 +                    // Validate the hour value in non-lenient
 38.1914 +                    if (value < 1 || value > 24) {
 38.1915 +                        break parsing;
 38.1916 +                    }
 38.1917 +                }
 38.1918 +                // [We computed 'value' above.]
 38.1919 +                if (value == calendar.getMaximum(Calendar.HOUR_OF_DAY)+1)
 38.1920 +                    value = 0;
 38.1921 +                calb.set(Calendar.HOUR_OF_DAY, value);
 38.1922 +                return pos.index;
 38.1923 +
 38.1924 +            case PATTERN_DAY_OF_WEEK:  // 'E'
 38.1925 +                {
 38.1926 +                    if (useDateFormatSymbols) {
 38.1927 +                        // Want to be able to parse both short and long forms.
 38.1928 +                        // Try count == 4 (DDDD) first:
 38.1929 +                        int newStart = 0;
 38.1930 +                        if ((newStart=matchString(text, start, Calendar.DAY_OF_WEEK,
 38.1931 +                                                  formatData.getWeekdays(), calb)) > 0) {
 38.1932 +                            return newStart;
 38.1933 +                        }
 38.1934 +                        // DDDD failed, now try DDD
 38.1935 +                        if ((index = matchString(text, start, Calendar.DAY_OF_WEEK,
 38.1936 +                                                 formatData.getShortWeekdays(), calb)) > 0) {
 38.1937 +                            return index;
 38.1938 +                        }
 38.1939 +                    } else {
 38.1940 +                        int[] styles = { Calendar.LONG, Calendar.SHORT };
 38.1941 +                        for (int style : styles) {
 38.1942 +                            Map<String,Integer> map = calendar.getDisplayNames(field, style, locale);
 38.1943 +                            if ((index = matchString(text, start, field, map, calb)) > 0) {
 38.1944 +                                return index;
 38.1945 +                            }
 38.1946 +                        }
 38.1947 +                    }
 38.1948 +                }
 38.1949 +                break parsing;
 38.1950 +
 38.1951 +            case PATTERN_AM_PM:    // 'a'
 38.1952 +                if (useDateFormatSymbols) {
 38.1953 +                    if ((index = matchString(text, start, Calendar.AM_PM,
 38.1954 +                                             formatData.getAmPmStrings(), calb)) > 0) {
 38.1955 +                        return index;
 38.1956 +                    }
 38.1957 +                } else {
 38.1958 +                    Map<String,Integer> map = calendar.getDisplayNames(field, Calendar.ALL_STYLES, locale);
 38.1959 +                    if ((index = matchString(text, start, field, map, calb)) > 0) {
 38.1960 +                        return index;
 38.1961 +                    }
 38.1962 +                }
 38.1963 +                break parsing;
 38.1964 +
 38.1965 +            case PATTERN_HOUR1: // 'h' 1-based.  eg, 11PM + 1 hour =>> 12 AM
 38.1966 +                if (!isLenient()) {
 38.1967 +                    // Validate the hour value in non-lenient
 38.1968 +                    if (value < 1 || value > 12) {
 38.1969 +                        break parsing;
 38.1970 +                    }
 38.1971 +                }
 38.1972 +                // [We computed 'value' above.]
 38.1973 +                if (value == calendar.getLeastMaximum(Calendar.HOUR)+1)
 38.1974 +                    value = 0;
 38.1975 +                calb.set(Calendar.HOUR, value);
 38.1976 +                return pos.index;
 38.1977 +
 38.1978 +            case PATTERN_ZONE_NAME:  // 'z'
 38.1979 +            case PATTERN_ZONE_VALUE: // 'Z'
 38.1980 +                {
 38.1981 +                    int sign = 0;
 38.1982 +                    try {
 38.1983 +                        char c = text.charAt(pos.index);
 38.1984 +                        if (c == '+') {
 38.1985 +                            sign = 1;
 38.1986 +                        } else if (c == '-') {
 38.1987 +                            sign = -1;
 38.1988 +                        }
 38.1989 +                        if (sign == 0) {
 38.1990 +                            // Try parsing a custom time zone "GMT+hh:mm" or "GMT".
 38.1991 +                            if ((c == 'G' || c == 'g')
 38.1992 +                                && (text.length() - start) >= GMT.length()
 38.1993 +                                && text.regionMatches(true, start, GMT, 0, GMT.length())) {
 38.1994 +                                pos.index = start + GMT.length();
 38.1995 +
 38.1996 +                                if ((text.length() - pos.index) > 0) {
 38.1997 +                                    c = text.charAt(pos.index);
 38.1998 +                                    if (c == '+') {
 38.1999 +                                        sign = 1;
 38.2000 +                                    } else if (c == '-') {
 38.2001 +                                        sign = -1;
 38.2002 +                                    }
 38.2003 +                                }
 38.2004 +
 38.2005 +                                if (sign == 0) {    /* "GMT" without offset */
 38.2006 +                                    calb.set(Calendar.ZONE_OFFSET, 0)
 38.2007 +                                        .set(Calendar.DST_OFFSET, 0);
 38.2008 +                                    return pos.index;
 38.2009 +                                }
 38.2010 +
 38.2011 +                                // Parse the rest as "hh:mm"
 38.2012 +                                int i = subParseNumericZone(text, ++pos.index,
 38.2013 +                                                            sign, 0, true, calb);
 38.2014 +                                if (i > 0) {
 38.2015 +                                    return i;
 38.2016 +                                }
 38.2017 +                                pos.index = -i;
 38.2018 +                            } else {
 38.2019 +                                // Try parsing the text as a time zone
 38.2020 +                                // name or abbreviation.
 38.2021 +                                int i = subParseZoneString(text, pos.index, calb);
 38.2022 +                                if (i > 0) {
 38.2023 +                                    return i;
 38.2024 +                                }
 38.2025 +                                pos.index = -i;
 38.2026 +                            }
 38.2027 +                        } else {
 38.2028 +                            // Parse the rest as "hhmm" (RFC 822)
 38.2029 +                            int i = subParseNumericZone(text, ++pos.index,
 38.2030 +                                                        sign, 0, false, calb);
 38.2031 +                            if (i > 0) {
 38.2032 +                                return i;
 38.2033 +                            }
 38.2034 +                            pos.index = -i;
 38.2035 +                        }
 38.2036 +                    } catch (IndexOutOfBoundsException e) {
 38.2037 +                    }
 38.2038 +                }
 38.2039 +                break parsing;
 38.2040 +
 38.2041 +            case PATTERN_ISO_ZONE:   // 'X'
 38.2042 +                {
 38.2043 +                    if ((text.length() - pos.index) <= 0) {
 38.2044 +                        break parsing;
 38.2045 +                    }
 38.2046 +
 38.2047 +                    int sign = 0;
 38.2048 +                    char c = text.charAt(pos.index);
 38.2049 +                    if (c == 'Z') {
 38.2050 +                        calb.set(Calendar.ZONE_OFFSET, 0).set(Calendar.DST_OFFSET, 0);
 38.2051 +                        return ++pos.index;
 38.2052 +                    }
 38.2053 +
 38.2054 +                    // parse text as "+/-hh[[:]mm]" based on count
 38.2055 +                    if (c == '+') {
 38.2056 +                        sign = 1;
 38.2057 +                    } else if (c == '-') {
 38.2058 +                        sign = -1;
 38.2059 +                    } else {
 38.2060 +                        ++pos.index;
 38.2061 +                        break parsing;
 38.2062 +                    }
 38.2063 +                    int i = subParseNumericZone(text, ++pos.index, sign, count,
 38.2064 +                                                count == 3, calb);
 38.2065 +                    if (i > 0) {
 38.2066 +                        return i;
 38.2067 +                    }
 38.2068 +                    pos.index = -i;
 38.2069 +                }
 38.2070 +                break parsing;
 38.2071 +
 38.2072 +            default:
 38.2073 +         // case PATTERN_DAY_OF_MONTH:         // 'd'
 38.2074 +         // case PATTERN_HOUR_OF_DAY0:         // 'H' 0-based.  eg, 23:59 + 1 hour =>> 00:59
 38.2075 +         // case PATTERN_MINUTE:               // 'm'
 38.2076 +         // case PATTERN_SECOND:               // 's'
 38.2077 +         // case PATTERN_MILLISECOND:          // 'S'
 38.2078 +         // case PATTERN_DAY_OF_YEAR:          // 'D'
 38.2079 +         // case PATTERN_DAY_OF_WEEK_IN_MONTH: // 'F'
 38.2080 +         // case PATTERN_WEEK_OF_YEAR:         // 'w'
 38.2081 +         // case PATTERN_WEEK_OF_MONTH:        // 'W'
 38.2082 +         // case PATTERN_HOUR0:                // 'K' 0-based.  eg, 11PM + 1 hour =>> 0 AM
 38.2083 +         // case PATTERN_ISO_DAY_OF_WEEK:      // 'u' (pseudo field);
 38.2084 +
 38.2085 +                // Handle "generic" fields
 38.2086 +                if (obeyCount) {
 38.2087 +                    if ((start+count) > text.length()) {
 38.2088 +                        break parsing;
 38.2089 +                    }
 38.2090 +                    number = numberFormat.parse(text.substring(0, start+count), pos);
 38.2091 +                } else {
 38.2092 +                    number = numberFormat.parse(text, pos);
 38.2093 +                }
 38.2094 +                if (number != null) {
 38.2095 +                    value = number.intValue();
 38.2096 +
 38.2097 +                    if (useFollowingMinusSignAsDelimiter && (value < 0) &&
 38.2098 +                        (((pos.index < text.length()) &&
 38.2099 +                         (text.charAt(pos.index) != minusSign)) ||
 38.2100 +                         ((pos.index == text.length()) &&
 38.2101 +                          (text.charAt(pos.index-1) == minusSign)))) {
 38.2102 +                        value = -value;
 38.2103 +                        pos.index--;
 38.2104 +                    }
 38.2105 +
 38.2106 +                    calb.set(field, value);
 38.2107 +                    return pos.index;
 38.2108 +                }
 38.2109 +                break parsing;
 38.2110 +            }
 38.2111 +        }
 38.2112 +
 38.2113 +        // Parsing failed.
 38.2114 +        origPos.errorIndex = pos.index;
 38.2115 +        return -1;
 38.2116 +    }
 38.2117 +
 38.2118 +    private final String getCalendarName() {
 38.2119 +        return calendar.getClass().getName();
 38.2120 +    }
 38.2121 +
 38.2122 +    private boolean useDateFormatSymbols() {
 38.2123 +        if (useDateFormatSymbols) {
 38.2124 +            return true;
 38.2125 +        }
 38.2126 +        return isGregorianCalendar() || locale == null;
 38.2127 +    }
 38.2128 +
 38.2129 +    private boolean isGregorianCalendar() {
 38.2130 +        return "java.util.GregorianCalendar".equals(getCalendarName());
 38.2131 +    }
 38.2132 +
 38.2133 +    /**
 38.2134 +     * Translates a pattern, mapping each character in the from string to the
 38.2135 +     * corresponding character in the to string.
 38.2136 +     *
 38.2137 +     * @exception IllegalArgumentException if the given pattern is invalid
 38.2138 +     */
 38.2139 +    private String translatePattern(String pattern, String from, String to) {
 38.2140 +        StringBuilder result = new StringBuilder();
 38.2141 +        boolean inQuote = false;
 38.2142 +        for (int i = 0; i < pattern.length(); ++i) {
 38.2143 +            char c = pattern.charAt(i);
 38.2144 +            if (inQuote) {
 38.2145 +                if (c == '\'')
 38.2146 +                    inQuote = false;
 38.2147 +            }
 38.2148 +            else {
 38.2149 +                if (c == '\'')
 38.2150 +                    inQuote = true;
 38.2151 +                else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
 38.2152 +                    int ci = from.indexOf(c);
 38.2153 +                    if (ci >= 0) {
 38.2154 +                        // patternChars is longer than localPatternChars due
 38.2155 +                        // to serialization compatibility. The pattern letters
 38.2156 +                        // unsupported by localPatternChars pass through.
 38.2157 +                        if (ci < to.length()) {
 38.2158 +                            c = to.charAt(ci);
 38.2159 +                        }
 38.2160 +                    } else {
 38.2161 +                        throw new IllegalArgumentException("Illegal pattern " +
 38.2162 +                                                           " character '" +
 38.2163 +                                                           c + "'");
 38.2164 +                    }
 38.2165 +                }
 38.2166 +            }
 38.2167 +            result.append(c);
 38.2168 +        }
 38.2169 +        if (inQuote)
 38.2170 +            throw new IllegalArgumentException("Unfinished quote in pattern");
 38.2171 +        return result.toString();
 38.2172 +    }
 38.2173 +
 38.2174 +    /**
 38.2175 +     * Returns a pattern string describing this date format.
 38.2176 +     *
 38.2177 +     * @return a pattern string describing this date format.
 38.2178 +     */
 38.2179 +    public String toPattern() {
 38.2180 +        return pattern;
 38.2181 +    }
 38.2182 +
 38.2183 +    /**
 38.2184 +     * Returns a localized pattern string describing this date format.
 38.2185 +     *
 38.2186 +     * @return a localized pattern string describing this date format.
 38.2187 +     */
 38.2188 +    public String toLocalizedPattern() {
 38.2189 +        return translatePattern(pattern,
 38.2190 +                                DateFormatSymbols.patternChars,
 38.2191 +                                formatData.getLocalPatternChars());
 38.2192 +    }
 38.2193 +
 38.2194 +    /**
 38.2195 +     * Applies the given pattern string to this date format.
 38.2196 +     *
 38.2197 +     * @param pattern the new date and time pattern for this date format
 38.2198 +     * @exception NullPointerException if the given pattern is null
 38.2199 +     * @exception IllegalArgumentException if the given pattern is invalid
 38.2200 +     */
 38.2201 +    public void applyPattern(String pattern)
 38.2202 +    {
 38.2203 +        compiledPattern = compile(pattern);
 38.2204 +        this.pattern = pattern;
 38.2205 +    }
 38.2206 +
 38.2207 +    /**
 38.2208 +     * Applies the given localized pattern string to this date format.
 38.2209 +     *
 38.2210 +     * @param pattern a String to be mapped to the new date and time format
 38.2211 +     *        pattern for this format
 38.2212 +     * @exception NullPointerException if the given pattern is null
 38.2213 +     * @exception IllegalArgumentException if the given pattern is invalid
 38.2214 +     */
 38.2215 +    public void applyLocalizedPattern(String pattern) {
 38.2216 +         String p = translatePattern(pattern,
 38.2217 +                                     formatData.getLocalPatternChars(),
 38.2218 +                                     DateFormatSymbols.patternChars);
 38.2219 +         compiledPattern = compile(p);
 38.2220 +         this.pattern = p;
 38.2221 +    }
 38.2222 +
 38.2223 +    /**
 38.2224 +     * Gets a copy of the date and time format symbols of this date format.
 38.2225 +     *
 38.2226 +     * @return the date and time format symbols of this date format
 38.2227 +     * @see #setDateFormatSymbols
 38.2228 +     */
 38.2229 +    public DateFormatSymbols getDateFormatSymbols()
 38.2230 +    {
 38.2231 +        return (DateFormatSymbols)formatData.clone();
 38.2232 +    }
 38.2233 +
 38.2234 +    /**
 38.2235 +     * Sets the date and time format symbols of this date format.
 38.2236 +     *
 38.2237 +     * @param newFormatSymbols the new date and time format symbols
 38.2238 +     * @exception NullPointerException if the given newFormatSymbols is null
 38.2239 +     * @see #getDateFormatSymbols
 38.2240 +     */
 38.2241 +    public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols)
 38.2242 +    {
 38.2243 +        this.formatData = (DateFormatSymbols)newFormatSymbols.clone();
 38.2244 +        useDateFormatSymbols = true;
 38.2245 +    }
 38.2246 +
 38.2247 +    /**
 38.2248 +     * Creates a copy of this <code>SimpleDateFormat</code>. This also
 38.2249 +     * clones the format's date format symbols.
 38.2250 +     *
 38.2251 +     * @return a clone of this <code>SimpleDateFormat</code>
 38.2252 +     */
 38.2253 +    public Object clone() {
 38.2254 +        SimpleDateFormat other = (SimpleDateFormat) super.clone();
 38.2255 +        other.formatData = (DateFormatSymbols) formatData.clone();
 38.2256 +        return other;
 38.2257 +    }
 38.2258 +
 38.2259 +    /**
 38.2260 +     * Returns the hash code value for this <code>SimpleDateFormat</code> object.
 38.2261 +     *
 38.2262 +     * @return the hash code value for this <code>SimpleDateFormat</code> object.
 38.2263 +     */
 38.2264 +    public int hashCode()
 38.2265 +    {
 38.2266 +        return pattern.hashCode();
 38.2267 +        // just enough fields for a reasonable distribution
 38.2268 +    }
 38.2269 +
 38.2270 +    /**
 38.2271 +     * Compares the given object with this <code>SimpleDateFormat</code> for
 38.2272 +     * equality.
 38.2273 +     *
 38.2274 +     * @return true if the given object is equal to this
 38.2275 +     * <code>SimpleDateFormat</code>
 38.2276 +     */
 38.2277 +    public boolean equals(Object obj)
 38.2278 +    {
 38.2279 +        if (!super.equals(obj)) return false; // super does class check
 38.2280 +        SimpleDateFormat that = (SimpleDateFormat) obj;
 38.2281 +        return (pattern.equals(that.pattern)
 38.2282 +                && formatData.equals(that.formatData));
 38.2283 +    }
 38.2284 +
 38.2285 +    /**
 38.2286 +     * After reading an object from the input stream, the format
 38.2287 +     * pattern in the object is verified.
 38.2288 +     * <p>
 38.2289 +     * @exception InvalidObjectException if the pattern is invalid
 38.2290 +     */
 38.2291 +    private void readObject(ObjectInputStream stream)
 38.2292 +                         throws IOException, ClassNotFoundException {
 38.2293 +        stream.defaultReadObject();
 38.2294 +
 38.2295 +        try {
 38.2296 +            compiledPattern = compile(pattern);
 38.2297 +        } catch (Exception e) {
 38.2298 +            throw new InvalidObjectException("invalid pattern");
 38.2299 +        }
 38.2300 +
 38.2301 +        if (serialVersionOnStream < 1) {
 38.2302 +            // didn't have defaultCenturyStart field
 38.2303 +            initializeDefaultCentury();
 38.2304 +        }
 38.2305 +        else {
 38.2306 +            // fill in dependent transient field
 38.2307 +            parseAmbiguousDatesAsAfter(defaultCenturyStart);
 38.2308 +        }
 38.2309 +        serialVersionOnStream = currentSerialVersion;
 38.2310 +
 38.2311 +        // If the deserialized object has a SimpleTimeZone, try
 38.2312 +        // to replace it with a ZoneInfo equivalent in order to
 38.2313 +        // be compatible with the SimpleTimeZone-based
 38.2314 +        // implementation as much as possible.
 38.2315 +        TimeZone tz = getTimeZone();
 38.2316 +        if (tz instanceof SimpleTimeZone) {
 38.2317 +            String id = tz.getID();
 38.2318 +            TimeZone zi = TimeZone.getTimeZone(id);
 38.2319 +            if (zi != null && zi.hasSameRules(tz) && zi.getID().equals(id)) {
 38.2320 +                setTimeZone(zi);
 38.2321 +            }
 38.2322 +        }
 38.2323 +    }
 38.2324 +
 38.2325 +    /**
 38.2326 +     * Analyze the negative subpattern of DecimalFormat and set/update values
 38.2327 +     * as necessary.
 38.2328 +     */
 38.2329 +    private void checkNegativeNumberExpression() {
 38.2330 +        if ((numberFormat instanceof DecimalFormat) &&
 38.2331 +            !numberFormat.equals(originalNumberFormat)) {
 38.2332 +            String numberPattern = ((DecimalFormat)numberFormat).toPattern();
 38.2333 +            if (!numberPattern.equals(originalNumberPattern)) {
 38.2334 +                hasFollowingMinusSign = false;
 38.2335 +
 38.2336 +                int separatorIndex = numberPattern.indexOf(';');
 38.2337 +                // If the negative subpattern is not absent, we have to analayze
 38.2338 +                // it in order to check if it has a following minus sign.
 38.2339 +                if (separatorIndex > -1) {
 38.2340 +                    int minusIndex = numberPattern.indexOf('-', separatorIndex);
 38.2341 +                    if ((minusIndex > numberPattern.lastIndexOf('0')) &&
 38.2342 +                        (minusIndex > numberPattern.lastIndexOf('#'))) {
 38.2343 +                        hasFollowingMinusSign = true;
 38.2344 +                        minusSign = ((DecimalFormat)numberFormat).getDecimalFormatSymbols().getMinusSign();
 38.2345 +                    }
 38.2346 +                }
 38.2347 +                originalNumberPattern = numberPattern;
 38.2348 +            }
 38.2349 +            originalNumberFormat = numberFormat;
 38.2350 +        }
 38.2351 +    }
 38.2352 +
 38.2353 +}
    39.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    39.2 +++ b/rt/emul/compact/src/main/java/java/util/Calendar.java	Thu Oct 03 15:40:35 2013 +0200
    39.3 @@ -0,0 +1,2824 @@
    39.4 +/*
    39.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    39.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    39.7 + *
    39.8 + * This code is free software; you can redistribute it and/or modify it
    39.9 + * under the terms of the GNU General Public License version 2 only, as
   39.10 + * published by the Free Software Foundation.  Oracle designates this
   39.11 + * particular file as subject to the "Classpath" exception as provided
   39.12 + * by Oracle in the LICENSE file that accompanied this code.
   39.13 + *
   39.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   39.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   39.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   39.17 + * version 2 for more details (a copy is included in the LICENSE file that
   39.18 + * accompanied this code).
   39.19 + *
   39.20 + * You should have received a copy of the GNU General Public License version
   39.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   39.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   39.23 + *
   39.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   39.25 + * or visit www.oracle.com if you need additional information or have any
   39.26 + * questions.
   39.27 + */
   39.28 +
   39.29 +/*
   39.30 + * (C) Copyright Taligent, Inc. 1996-1998 - All Rights Reserved
   39.31 + * (C) Copyright IBM Corp. 1996-1998 - All Rights Reserved
   39.32 + *
   39.33 + *   The original version of this source code and documentation is copyrighted
   39.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   39.35 + * materials are provided under terms of a License Agreement between Taligent
   39.36 + * and Sun. This technology is protected by multiple US and International
   39.37 + * patents. This notice and attribution to Taligent may not be removed.
   39.38 + *   Taligent is a registered trademark of Taligent, Inc.
   39.39 + *
   39.40 + */
   39.41 +
   39.42 +package java.util;
   39.43 +
   39.44 +import java.io.IOException;
   39.45 +import java.io.ObjectInputStream;
   39.46 +import java.io.ObjectOutputStream;
   39.47 +import java.io.OptionalDataException;
   39.48 +import java.io.Serializable;
   39.49 +import java.security.AccessControlContext;
   39.50 +import java.security.AccessController;
   39.51 +import java.security.PermissionCollection;
   39.52 +import java.security.PrivilegedActionException;
   39.53 +import java.security.PrivilegedExceptionAction;
   39.54 +import java.security.ProtectionDomain;
   39.55 +import java.text.DateFormat;
   39.56 +import java.text.DateFormatSymbols;
   39.57 +import java.util.concurrent.ConcurrentHashMap;
   39.58 +import java.util.concurrent.ConcurrentMap;
   39.59 +import sun.util.BuddhistCalendar;
   39.60 +import sun.util.calendar.ZoneInfo;
   39.61 +import sun.util.resources.LocaleData;
   39.62 +
   39.63 +/**
   39.64 + * The <code>Calendar</code> class is an abstract class that provides methods
   39.65 + * for converting between a specific instant in time and a set of {@link
   39.66 + * #fields calendar fields} such as <code>YEAR</code>, <code>MONTH</code>,
   39.67 + * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, and so on, and for
   39.68 + * manipulating the calendar fields, such as getting the date of the next
   39.69 + * week. An instant in time can be represented by a millisecond value that is
   39.70 + * an offset from the <a name="Epoch"><em>Epoch</em></a>, January 1, 1970
   39.71 + * 00:00:00.000 GMT (Gregorian).
   39.72 + *
   39.73 + * <p>The class also provides additional fields and methods for
   39.74 + * implementing a concrete calendar system outside the package. Those
   39.75 + * fields and methods are defined as <code>protected</code>.
   39.76 + *
   39.77 + * <p>
   39.78 + * Like other locale-sensitive classes, <code>Calendar</code> provides a
   39.79 + * class method, <code>getInstance</code>, for getting a generally useful
   39.80 + * object of this type. <code>Calendar</code>'s <code>getInstance</code> method
   39.81 + * returns a <code>Calendar</code> object whose
   39.82 + * calendar fields have been initialized with the current date and time:
   39.83 + * <blockquote>
   39.84 + * <pre>
   39.85 + *     Calendar rightNow = Calendar.getInstance();
   39.86 + * </pre>
   39.87 + * </blockquote>
   39.88 + *
   39.89 + * <p>A <code>Calendar</code> object can produce all the calendar field values
   39.90 + * needed to implement the date-time formatting for a particular language and
   39.91 + * calendar style (for example, Japanese-Gregorian, Japanese-Traditional).
   39.92 + * <code>Calendar</code> defines the range of values returned by
   39.93 + * certain calendar fields, as well as their meaning.  For example,
   39.94 + * the first month of the calendar system has value <code>MONTH ==
   39.95 + * JANUARY</code> for all calendars.  Other values are defined by the
   39.96 + * concrete subclass, such as <code>ERA</code>.  See individual field
   39.97 + * documentation and subclass documentation for details.
   39.98 + *
   39.99 + * <h4>Getting and Setting Calendar Field Values</h4>
  39.100 + *
  39.101 + * <p>The calendar field values can be set by calling the <code>set</code>
  39.102 + * methods. Any field values set in a <code>Calendar</code> will not be
  39.103 + * interpreted until it needs to calculate its time value (milliseconds from
  39.104 + * the Epoch) or values of the calendar fields. Calling the
  39.105 + * <code>get</code>, <code>getTimeInMillis</code>, <code>getTime</code>,
  39.106 + * <code>add</code> and <code>roll</code> involves such calculation.
  39.107 + *
  39.108 + * <h4>Leniency</h4>
  39.109 + *
  39.110 + * <p><code>Calendar</code> has two modes for interpreting the calendar
  39.111 + * fields, <em>lenient</em> and <em>non-lenient</em>.  When a
  39.112 + * <code>Calendar</code> is in lenient mode, it accepts a wider range of
  39.113 + * calendar field values than it produces.  When a <code>Calendar</code>
  39.114 + * recomputes calendar field values for return by <code>get()</code>, all of
  39.115 + * the calendar fields are normalized. For example, a lenient
  39.116 + * <code>GregorianCalendar</code> interprets <code>MONTH == JANUARY</code>,
  39.117 + * <code>DAY_OF_MONTH == 32</code> as February 1.
  39.118 +
  39.119 + * <p>When a <code>Calendar</code> is in non-lenient mode, it throws an
  39.120 + * exception if there is any inconsistency in its calendar fields. For
  39.121 + * example, a <code>GregorianCalendar</code> always produces
  39.122 + * <code>DAY_OF_MONTH</code> values between 1 and the length of the month. A
  39.123 + * non-lenient <code>GregorianCalendar</code> throws an exception upon
  39.124 + * calculating its time or calendar field values if any out-of-range field
  39.125 + * value has been set.
  39.126 + *
  39.127 + * <h4><a name="first_week">First Week</a></h4>
  39.128 + *
  39.129 + * <code>Calendar</code> defines a locale-specific seven day week using two
  39.130 + * parameters: the first day of the week and the minimal days in first week
  39.131 + * (from 1 to 7).  These numbers are taken from the locale resource data when a
  39.132 + * <code>Calendar</code> is constructed.  They may also be specified explicitly
  39.133 + * through the methods for setting their values.
  39.134 + *
  39.135 + * <p>When setting or getting the <code>WEEK_OF_MONTH</code> or
  39.136 + * <code>WEEK_OF_YEAR</code> fields, <code>Calendar</code> must determine the
  39.137 + * first week of the month or year as a reference point.  The first week of a
  39.138 + * month or year is defined as the earliest seven day period beginning on
  39.139 + * <code>getFirstDayOfWeek()</code> and containing at least
  39.140 + * <code>getMinimalDaysInFirstWeek()</code> days of that month or year.  Weeks
  39.141 + * numbered ..., -1, 0 precede the first week; weeks numbered 2, 3,... follow
  39.142 + * it.  Note that the normalized numbering returned by <code>get()</code> may be
  39.143 + * different.  For example, a specific <code>Calendar</code> subclass may
  39.144 + * designate the week before week 1 of a year as week <code><i>n</i></code> of
  39.145 + * the previous year.
  39.146 + *
  39.147 + * <h4>Calendar Fields Resolution</h4>
  39.148 + *
  39.149 + * When computing a date and time from the calendar fields, there
  39.150 + * may be insufficient information for the computation (such as only
  39.151 + * year and month with no day of month), or there may be inconsistent
  39.152 + * information (such as Tuesday, July 15, 1996 (Gregorian) -- July 15,
  39.153 + * 1996 is actually a Monday). <code>Calendar</code> will resolve
  39.154 + * calendar field values to determine the date and time in the
  39.155 + * following way.
  39.156 + *
  39.157 + * <p>If there is any conflict in calendar field values,
  39.158 + * <code>Calendar</code> gives priorities to calendar fields that have been set
  39.159 + * more recently. The following are the default combinations of the
  39.160 + * calendar fields. The most recent combination, as determined by the
  39.161 + * most recently set single field, will be used.
  39.162 + *
  39.163 + * <p><a name="date_resolution">For the date fields</a>:
  39.164 + * <blockquote>
  39.165 + * <pre>
  39.166 + * YEAR + MONTH + DAY_OF_MONTH
  39.167 + * YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
  39.168 + * YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
  39.169 + * YEAR + DAY_OF_YEAR
  39.170 + * YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
  39.171 + * </pre></blockquote>
  39.172 + *
  39.173 + * <a name="time_resolution">For the time of day fields</a>:
  39.174 + * <blockquote>
  39.175 + * <pre>
  39.176 + * HOUR_OF_DAY
  39.177 + * AM_PM + HOUR
  39.178 + * </pre></blockquote>
  39.179 + *
  39.180 + * <p>If there are any calendar fields whose values haven't been set in the selected
  39.181 + * field combination, <code>Calendar</code> uses their default values. The default
  39.182 + * value of each field may vary by concrete calendar systems. For example, in
  39.183 + * <code>GregorianCalendar</code>, the default of a field is the same as that
  39.184 + * of the start of the Epoch: i.e., <code>YEAR = 1970</code>, <code>MONTH =
  39.185 + * JANUARY</code>, <code>DAY_OF_MONTH = 1</code>, etc.
  39.186 + *
  39.187 + * <p>
  39.188 + * <strong>Note:</strong> There are certain possible ambiguities in
  39.189 + * interpretation of certain singular times, which are resolved in the
  39.190 + * following ways:
  39.191 + * <ol>
  39.192 + *     <li> 23:59 is the last minute of the day and 00:00 is the first
  39.193 + *          minute of the next day. Thus, 23:59 on Dec 31, 1999 &lt; 00:00 on
  39.194 + *          Jan 1, 2000 &lt; 00:01 on Jan 1, 2000.
  39.195 + *
  39.196 + *     <li> Although historically not precise, midnight also belongs to "am",
  39.197 + *          and noon belongs to "pm", so on the same day,
  39.198 + *          12:00 am (midnight) &lt; 12:01 am, and 12:00 pm (noon) &lt; 12:01 pm
  39.199 + * </ol>
  39.200 + *
  39.201 + * <p>
  39.202 + * The date or time format strings are not part of the definition of a
  39.203 + * calendar, as those must be modifiable or overridable by the user at
  39.204 + * runtime. Use {@link DateFormat}
  39.205 + * to format dates.
  39.206 + *
  39.207 + * <h4>Field Manipulation</h4>
  39.208 + *
  39.209 + * The calendar fields can be changed using three methods:
  39.210 + * <code>set()</code>, <code>add()</code>, and <code>roll()</code>.</p>
  39.211 + *
  39.212 + * <p><strong><code>set(f, value)</code></strong> changes calendar field
  39.213 + * <code>f</code> to <code>value</code>.  In addition, it sets an
  39.214 + * internal member variable to indicate that calendar field <code>f</code> has
  39.215 + * been changed. Although calendar field <code>f</code> is changed immediately,
  39.216 + * the calendar's time value in milliseconds is not recomputed until the next call to
  39.217 + * <code>get()</code>, <code>getTime()</code>, <code>getTimeInMillis()</code>,
  39.218 + * <code>add()</code>, or <code>roll()</code> is made. Thus, multiple calls to
  39.219 + * <code>set()</code> do not trigger multiple, unnecessary
  39.220 + * computations. As a result of changing a calendar field using
  39.221 + * <code>set()</code>, other calendar fields may also change, depending on the
  39.222 + * calendar field, the calendar field value, and the calendar system. In addition,
  39.223 + * <code>get(f)</code> will not necessarily return <code>value</code> set by
  39.224 + * the call to the <code>set</code> method
  39.225 + * after the calendar fields have been recomputed. The specifics are determined by
  39.226 + * the concrete calendar class.</p>
  39.227 + *
  39.228 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
  39.229 + * originally set to August 31, 1999. Calling <code>set(Calendar.MONTH,
  39.230 + * Calendar.SEPTEMBER)</code> sets the date to September 31,
  39.231 + * 1999. This is a temporary internal representation that resolves to
  39.232 + * October 1, 1999 if <code>getTime()</code>is then called. However, a
  39.233 + * call to <code>set(Calendar.DAY_OF_MONTH, 30)</code> before the call to
  39.234 + * <code>getTime()</code> sets the date to September 30, 1999, since
  39.235 + * no recomputation occurs after <code>set()</code> itself.</p>
  39.236 + *
  39.237 + * <p><strong><code>add(f, delta)</code></strong> adds <code>delta</code>
  39.238 + * to field <code>f</code>.  This is equivalent to calling <code>set(f,
  39.239 + * get(f) + delta)</code> with two adjustments:</p>
  39.240 + *
  39.241 + * <blockquote>
  39.242 + *   <p><strong>Add rule 1</strong>. The value of field <code>f</code>
  39.243 + *   after the call minus the value of field <code>f</code> before the
  39.244 + *   call is <code>delta</code>, modulo any overflow that has occurred in
  39.245 + *   field <code>f</code>. Overflow occurs when a field value exceeds its
  39.246 + *   range and, as a result, the next larger field is incremented or
  39.247 + *   decremented and the field value is adjusted back into its range.</p>
  39.248 + *
  39.249 + *   <p><strong>Add rule 2</strong>. If a smaller field is expected to be
  39.250 + *   invariant, but it is impossible for it to be equal to its
  39.251 + *   prior value because of changes in its minimum or maximum after field
  39.252 + *   <code>f</code> is changed or other constraints, such as time zone
  39.253 + *   offset changes, then its value is adjusted to be as close
  39.254 + *   as possible to its expected value. A smaller field represents a
  39.255 + *   smaller unit of time. <code>HOUR</code> is a smaller field than
  39.256 + *   <code>DAY_OF_MONTH</code>. No adjustment is made to smaller fields
  39.257 + *   that are not expected to be invariant. The calendar system
  39.258 + *   determines what fields are expected to be invariant.</p>
  39.259 + * </blockquote>
  39.260 + *
  39.261 + * <p>In addition, unlike <code>set()</code>, <code>add()</code> forces
  39.262 + * an immediate recomputation of the calendar's milliseconds and all
  39.263 + * fields.</p>
  39.264 + *
  39.265 + * <p><em>Example</em>: Consider a <code>GregorianCalendar</code>
  39.266 + * originally set to August 31, 1999. Calling <code>add(Calendar.MONTH,
  39.267 + * 13)</code> sets the calendar to September 30, 2000. <strong>Add rule
  39.268 + * 1</strong> sets the <code>MONTH</code> field to September, since
  39.269 + * adding 13 months to August gives September of the next year. Since
  39.270 + * <code>DAY_OF_MONTH</code> cannot be 31 in September in a
  39.271 + * <code>GregorianCalendar</code>, <strong>add rule 2</strong> sets the
  39.272 + * <code>DAY_OF_MONTH</code> to 30, the closest possible value. Although
  39.273 + * it is a smaller field, <code>DAY_OF_WEEK</code> is not adjusted by
  39.274 + * rule 2, since it is expected to change when the month changes in a
  39.275 + * <code>GregorianCalendar</code>.</p>
  39.276 + *
  39.277 + * <p><strong><code>roll(f, delta)</code></strong> adds
  39.278 + * <code>delta</code> to field <code>f</code> without changing larger
  39.279 + * fields. This is equivalent to calling <code>add(f, delta)</code> with
  39.280 + * the following adjustment:</p>
  39.281 + *
  39.282 + * <blockquote>
  39.283 + *   <p><strong>Roll rule</strong>. Larger fields are unchanged after the
  39.284 + *   call. A larger field represents a larger unit of
  39.285 + *   time. <code>DAY_OF_MONTH</code> is a larger field than
  39.286 + *   <code>HOUR</code>.</p>
  39.287 + * </blockquote>
  39.288 + *
  39.289 + * <p><em>Example</em>: See {@link java.util.GregorianCalendar#roll(int, int)}.
  39.290 + *
  39.291 + * <p><strong>Usage model</strong>. To motivate the behavior of
  39.292 + * <code>add()</code> and <code>roll()</code>, consider a user interface
  39.293 + * component with increment and decrement buttons for the month, day, and
  39.294 + * year, and an underlying <code>GregorianCalendar</code>. If the
  39.295 + * interface reads January 31, 1999 and the user presses the month
  39.296 + * increment button, what should it read? If the underlying
  39.297 + * implementation uses <code>set()</code>, it might read March 3, 1999. A
  39.298 + * better result would be February 28, 1999. Furthermore, if the user
  39.299 + * presses the month increment button again, it should read March 31,
  39.300 + * 1999, not March 28, 1999. By saving the original date and using either
  39.301 + * <code>add()</code> or <code>roll()</code>, depending on whether larger
  39.302 + * fields should be affected, the user interface can behave as most users
  39.303 + * will intuitively expect.</p>
  39.304 + *
  39.305 + * @see          java.lang.System#currentTimeMillis()
  39.306 + * @see          Date
  39.307 + * @see          GregorianCalendar
  39.308 + * @see          TimeZone
  39.309 + * @see          java.text.DateFormat
  39.310 + * @author Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
  39.311 + * @since JDK1.1
  39.312 + */
  39.313 +public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
  39.314 +
  39.315 +    // Data flow in Calendar
  39.316 +    // ---------------------
  39.317 +
  39.318 +    // The current time is represented in two ways by Calendar: as UTC
  39.319 +    // milliseconds from the epoch (1 January 1970 0:00 UTC), and as local
  39.320 +    // fields such as MONTH, HOUR, AM_PM, etc.  It is possible to compute the
  39.321 +    // millis from the fields, and vice versa.  The data needed to do this
  39.322 +    // conversion is encapsulated by a TimeZone object owned by the Calendar.
  39.323 +    // The data provided by the TimeZone object may also be overridden if the
  39.324 +    // user sets the ZONE_OFFSET and/or DST_OFFSET fields directly. The class
  39.325 +    // keeps track of what information was most recently set by the caller, and
  39.326 +    // uses that to compute any other information as needed.
  39.327 +
  39.328 +    // If the user sets the fields using set(), the data flow is as follows.
  39.329 +    // This is implemented by the Calendar subclass's computeTime() method.
  39.330 +    // During this process, certain fields may be ignored.  The disambiguation
  39.331 +    // algorithm for resolving which fields to pay attention to is described
  39.332 +    // in the class documentation.
  39.333 +
  39.334 +    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
  39.335 +    //           |
  39.336 +    //           | Using Calendar-specific algorithm
  39.337 +    //           V
  39.338 +    //   local standard millis
  39.339 +    //           |
  39.340 +    //           | Using TimeZone or user-set ZONE_OFFSET / DST_OFFSET
  39.341 +    //           V
  39.342 +    //   UTC millis (in time data member)
  39.343 +
  39.344 +    // If the user sets the UTC millis using setTime() or setTimeInMillis(),
  39.345 +    // the data flow is as follows.  This is implemented by the Calendar
  39.346 +    // subclass's computeFields() method.
  39.347 +
  39.348 +    //   UTC millis (in time data member)
  39.349 +    //           |
  39.350 +    //           | Using TimeZone getOffset()
  39.351 +    //           V
  39.352 +    //   local standard millis
  39.353 +    //           |
  39.354 +    //           | Using Calendar-specific algorithm
  39.355 +    //           V
  39.356 +    //   local fields (YEAR, MONTH, DATE, HOUR, MINUTE, etc.)
  39.357 +
  39.358 +    // In general, a round trip from fields, through local and UTC millis, and
  39.359 +    // back out to fields is made when necessary.  This is implemented by the
  39.360 +    // complete() method.  Resolving a partial set of fields into a UTC millis
  39.361 +    // value allows all remaining fields to be generated from that value.  If
  39.362 +    // the Calendar is lenient, the fields are also renormalized to standard
  39.363 +    // ranges when they are regenerated.
  39.364 +
  39.365 +    /**
  39.366 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.367 +     * era, e.g., AD or BC in the Julian calendar. This is a calendar-specific
  39.368 +     * value; see subclass documentation.
  39.369 +     *
  39.370 +     * @see GregorianCalendar#AD
  39.371 +     * @see GregorianCalendar#BC
  39.372 +     */
  39.373 +    public final static int ERA = 0;
  39.374 +
  39.375 +    /**
  39.376 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.377 +     * year. This is a calendar-specific value; see subclass documentation.
  39.378 +     */
  39.379 +    public final static int YEAR = 1;
  39.380 +
  39.381 +    /**
  39.382 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.383 +     * month. This is a calendar-specific value. The first month of
  39.384 +     * the year in the Gregorian and Julian calendars is
  39.385 +     * <code>JANUARY</code> which is 0; the last depends on the number
  39.386 +     * of months in a year.
  39.387 +     *
  39.388 +     * @see #JANUARY
  39.389 +     * @see #FEBRUARY
  39.390 +     * @see #MARCH
  39.391 +     * @see #APRIL
  39.392 +     * @see #MAY
  39.393 +     * @see #JUNE
  39.394 +     * @see #JULY
  39.395 +     * @see #AUGUST
  39.396 +     * @see #SEPTEMBER
  39.397 +     * @see #OCTOBER
  39.398 +     * @see #NOVEMBER
  39.399 +     * @see #DECEMBER
  39.400 +     * @see #UNDECIMBER
  39.401 +     */
  39.402 +    public final static int MONTH = 2;
  39.403 +
  39.404 +    /**
  39.405 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.406 +     * week number within the current year.  The first week of the year, as
  39.407 +     * defined by <code>getFirstDayOfWeek()</code> and
  39.408 +     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
  39.409 +     * the value of <code>WEEK_OF_YEAR</code> for days before the first week of
  39.410 +     * the year.
  39.411 +     *
  39.412 +     * @see #getFirstDayOfWeek
  39.413 +     * @see #getMinimalDaysInFirstWeek
  39.414 +     */
  39.415 +    public final static int WEEK_OF_YEAR = 3;
  39.416 +
  39.417 +    /**
  39.418 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.419 +     * week number within the current month.  The first week of the month, as
  39.420 +     * defined by <code>getFirstDayOfWeek()</code> and
  39.421 +     * <code>getMinimalDaysInFirstWeek()</code>, has value 1.  Subclasses define
  39.422 +     * the value of <code>WEEK_OF_MONTH</code> for days before the first week of
  39.423 +     * the month.
  39.424 +     *
  39.425 +     * @see #getFirstDayOfWeek
  39.426 +     * @see #getMinimalDaysInFirstWeek
  39.427 +     */
  39.428 +    public final static int WEEK_OF_MONTH = 4;
  39.429 +
  39.430 +    /**
  39.431 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.432 +     * day of the month. This is a synonym for <code>DAY_OF_MONTH</code>.
  39.433 +     * The first day of the month has value 1.
  39.434 +     *
  39.435 +     * @see #DAY_OF_MONTH
  39.436 +     */
  39.437 +    public final static int DATE = 5;
  39.438 +
  39.439 +    /**
  39.440 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.441 +     * day of the month. This is a synonym for <code>DATE</code>.
  39.442 +     * The first day of the month has value 1.
  39.443 +     *
  39.444 +     * @see #DATE
  39.445 +     */
  39.446 +    public final static int DAY_OF_MONTH = 5;
  39.447 +
  39.448 +    /**
  39.449 +     * Field number for <code>get</code> and <code>set</code> indicating the day
  39.450 +     * number within the current year.  The first day of the year has value 1.
  39.451 +     */
  39.452 +    public final static int DAY_OF_YEAR = 6;
  39.453 +
  39.454 +    /**
  39.455 +     * Field number for <code>get</code> and <code>set</code> indicating the day
  39.456 +     * of the week.  This field takes values <code>SUNDAY</code>,
  39.457 +     * <code>MONDAY</code>, <code>TUESDAY</code>, <code>WEDNESDAY</code>,
  39.458 +     * <code>THURSDAY</code>, <code>FRIDAY</code>, and <code>SATURDAY</code>.
  39.459 +     *
  39.460 +     * @see #SUNDAY
  39.461 +     * @see #MONDAY
  39.462 +     * @see #TUESDAY
  39.463 +     * @see #WEDNESDAY
  39.464 +     * @see #THURSDAY
  39.465 +     * @see #FRIDAY
  39.466 +     * @see #SATURDAY
  39.467 +     */
  39.468 +    public final static int DAY_OF_WEEK = 7;
  39.469 +
  39.470 +    /**
  39.471 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.472 +     * ordinal number of the day of the week within the current month. Together
  39.473 +     * with the <code>DAY_OF_WEEK</code> field, this uniquely specifies a day
  39.474 +     * within a month.  Unlike <code>WEEK_OF_MONTH</code> and
  39.475 +     * <code>WEEK_OF_YEAR</code>, this field's value does <em>not</em> depend on
  39.476 +     * <code>getFirstDayOfWeek()</code> or
  39.477 +     * <code>getMinimalDaysInFirstWeek()</code>.  <code>DAY_OF_MONTH 1</code>
  39.478 +     * through <code>7</code> always correspond to <code>DAY_OF_WEEK_IN_MONTH
  39.479 +     * 1</code>; <code>8</code> through <code>14</code> correspond to
  39.480 +     * <code>DAY_OF_WEEK_IN_MONTH 2</code>, and so on.
  39.481 +     * <code>DAY_OF_WEEK_IN_MONTH 0</code> indicates the week before
  39.482 +     * <code>DAY_OF_WEEK_IN_MONTH 1</code>.  Negative values count back from the
  39.483 +     * end of the month, so the last Sunday of a month is specified as
  39.484 +     * <code>DAY_OF_WEEK = SUNDAY, DAY_OF_WEEK_IN_MONTH = -1</code>.  Because
  39.485 +     * negative values count backward they will usually be aligned differently
  39.486 +     * within the month than positive values.  For example, if a month has 31
  39.487 +     * days, <code>DAY_OF_WEEK_IN_MONTH -1</code> will overlap
  39.488 +     * <code>DAY_OF_WEEK_IN_MONTH 5</code> and the end of <code>4</code>.
  39.489 +     *
  39.490 +     * @see #DAY_OF_WEEK
  39.491 +     * @see #WEEK_OF_MONTH
  39.492 +     */
  39.493 +    public final static int DAY_OF_WEEK_IN_MONTH = 8;
  39.494 +
  39.495 +    /**
  39.496 +     * Field number for <code>get</code> and <code>set</code> indicating
  39.497 +     * whether the <code>HOUR</code> is before or after noon.
  39.498 +     * E.g., at 10:04:15.250 PM the <code>AM_PM</code> is <code>PM</code>.
  39.499 +     *
  39.500 +     * @see #AM
  39.501 +     * @see #PM
  39.502 +     * @see #HOUR
  39.503 +     */
  39.504 +    public final static int AM_PM = 9;
  39.505 +
  39.506 +    /**
  39.507 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.508 +     * hour of the morning or afternoon. <code>HOUR</code> is used for the
  39.509 +     * 12-hour clock (0 - 11). Noon and midnight are represented by 0, not by 12.
  39.510 +     * E.g., at 10:04:15.250 PM the <code>HOUR</code> is 10.
  39.511 +     *
  39.512 +     * @see #AM_PM
  39.513 +     * @see #HOUR_OF_DAY
  39.514 +     */
  39.515 +    public final static int HOUR = 10;
  39.516 +
  39.517 +    /**
  39.518 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.519 +     * hour of the day. <code>HOUR_OF_DAY</code> is used for the 24-hour clock.
  39.520 +     * E.g., at 10:04:15.250 PM the <code>HOUR_OF_DAY</code> is 22.
  39.521 +     *
  39.522 +     * @see #HOUR
  39.523 +     */
  39.524 +    public final static int HOUR_OF_DAY = 11;
  39.525 +
  39.526 +    /**
  39.527 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.528 +     * minute within the hour.
  39.529 +     * E.g., at 10:04:15.250 PM the <code>MINUTE</code> is 4.
  39.530 +     */
  39.531 +    public final static int MINUTE = 12;
  39.532 +
  39.533 +    /**
  39.534 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.535 +     * second within the minute.
  39.536 +     * E.g., at 10:04:15.250 PM the <code>SECOND</code> is 15.
  39.537 +     */
  39.538 +    public final static int SECOND = 13;
  39.539 +
  39.540 +    /**
  39.541 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.542 +     * millisecond within the second.
  39.543 +     * E.g., at 10:04:15.250 PM the <code>MILLISECOND</code> is 250.
  39.544 +     */
  39.545 +    public final static int MILLISECOND = 14;
  39.546 +
  39.547 +    /**
  39.548 +     * Field number for <code>get</code> and <code>set</code>
  39.549 +     * indicating the raw offset from GMT in milliseconds.
  39.550 +     * <p>
  39.551 +     * This field reflects the correct GMT offset value of the time
  39.552 +     * zone of this <code>Calendar</code> if the
  39.553 +     * <code>TimeZone</code> implementation subclass supports
  39.554 +     * historical GMT offset changes.
  39.555 +     */
  39.556 +    public final static int ZONE_OFFSET = 15;
  39.557 +
  39.558 +    /**
  39.559 +     * Field number for <code>get</code> and <code>set</code> indicating the
  39.560 +     * daylight saving offset in milliseconds.
  39.561 +     * <p>
  39.562 +     * This field reflects the correct daylight saving offset value of
  39.563 +     * the time zone of this <code>Calendar</code> if the
  39.564 +     * <code>TimeZone</code> implementation subclass supports
  39.565 +     * historical Daylight Saving Time schedule changes.
  39.566 +     */
  39.567 +    public final static int DST_OFFSET = 16;
  39.568 +
  39.569 +    /**
  39.570 +     * The number of distinct fields recognized by <code>get</code> and <code>set</code>.
  39.571 +     * Field numbers range from <code>0..FIELD_COUNT-1</code>.
  39.572 +     */
  39.573 +    public final static int FIELD_COUNT = 17;
  39.574 +
  39.575 +    /**
  39.576 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.577 +     * Sunday.
  39.578 +     */
  39.579 +    public final static int SUNDAY = 1;
  39.580 +
  39.581 +    /**
  39.582 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.583 +     * Monday.
  39.584 +     */
  39.585 +    public final static int MONDAY = 2;
  39.586 +
  39.587 +    /**
  39.588 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.589 +     * Tuesday.
  39.590 +     */
  39.591 +    public final static int TUESDAY = 3;
  39.592 +
  39.593 +    /**
  39.594 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.595 +     * Wednesday.
  39.596 +     */
  39.597 +    public final static int WEDNESDAY = 4;
  39.598 +
  39.599 +    /**
  39.600 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.601 +     * Thursday.
  39.602 +     */
  39.603 +    public final static int THURSDAY = 5;
  39.604 +
  39.605 +    /**
  39.606 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.607 +     * Friday.
  39.608 +     */
  39.609 +    public final static int FRIDAY = 6;
  39.610 +
  39.611 +    /**
  39.612 +     * Value of the {@link #DAY_OF_WEEK} field indicating
  39.613 +     * Saturday.
  39.614 +     */
  39.615 +    public final static int SATURDAY = 7;
  39.616 +
  39.617 +    /**
  39.618 +     * Value of the {@link #MONTH} field indicating the
  39.619 +     * first month of the year in the Gregorian and Julian calendars.
  39.620 +     */
  39.621 +    public final static int JANUARY = 0;
  39.622 +
  39.623 +    /**
  39.624 +     * Value of the {@link #MONTH} field indicating the
  39.625 +     * second month of the year in the Gregorian and Julian calendars.
  39.626 +     */
  39.627 +    public final static int FEBRUARY = 1;
  39.628 +
  39.629 +    /**
  39.630 +     * Value of the {@link #MONTH} field indicating the
  39.631 +     * third month of the year in the Gregorian and Julian calendars.
  39.632 +     */
  39.633 +    public final static int MARCH = 2;
  39.634 +
  39.635 +    /**
  39.636 +     * Value of the {@link #MONTH} field indicating the
  39.637 +     * fourth month of the year in the Gregorian and Julian calendars.
  39.638 +     */
  39.639 +    public final static int APRIL = 3;
  39.640 +
  39.641 +    /**
  39.642 +     * Value of the {@link #MONTH} field indicating the
  39.643 +     * fifth month of the year in the Gregorian and Julian calendars.
  39.644 +     */
  39.645 +    public final static int MAY = 4;
  39.646 +
  39.647 +    /**
  39.648 +     * Value of the {@link #MONTH} field indicating the
  39.649 +     * sixth month of the year in the Gregorian and Julian calendars.
  39.650 +     */
  39.651 +    public final static int JUNE = 5;
  39.652 +
  39.653 +    /**
  39.654 +     * Value of the {@link #MONTH} field indicating the
  39.655 +     * seventh month of the year in the Gregorian and Julian calendars.
  39.656 +     */
  39.657 +    public final static int JULY = 6;
  39.658 +
  39.659 +    /**
  39.660 +     * Value of the {@link #MONTH} field indicating the
  39.661 +     * eighth month of the year in the Gregorian and Julian calendars.
  39.662 +     */
  39.663 +    public final static int AUGUST = 7;
  39.664 +
  39.665 +    /**
  39.666 +     * Value of the {@link #MONTH} field indicating the
  39.667 +     * ninth month of the year in the Gregorian and Julian calendars.
  39.668 +     */
  39.669 +    public final static int SEPTEMBER = 8;
  39.670 +
  39.671 +    /**
  39.672 +     * Value of the {@link #MONTH} field indicating the
  39.673 +     * tenth month of the year in the Gregorian and Julian calendars.
  39.674 +     */
  39.675 +    public final static int OCTOBER = 9;
  39.676 +
  39.677 +    /**
  39.678 +     * Value of the {@link #MONTH} field indicating the
  39.679 +     * eleventh month of the year in the Gregorian and Julian calendars.
  39.680 +     */
  39.681 +    public final static int NOVEMBER = 10;
  39.682 +
  39.683 +    /**
  39.684 +     * Value of the {@link #MONTH} field indicating the
  39.685 +     * twelfth month of the year in the Gregorian and Julian calendars.
  39.686 +     */
  39.687 +    public final static int DECEMBER = 11;
  39.688 +
  39.689 +    /**
  39.690 +     * Value of the {@link #MONTH} field indicating the
  39.691 +     * thirteenth month of the year. Although <code>GregorianCalendar</code>
  39.692 +     * does not use this value, lunar calendars do.
  39.693 +     */
  39.694 +    public final static int UNDECIMBER = 12;
  39.695 +
  39.696 +    /**
  39.697 +     * Value of the {@link #AM_PM} field indicating the
  39.698 +     * period of the day from midnight to just before noon.
  39.699 +     */
  39.700 +    public final static int AM = 0;
  39.701 +
  39.702 +    /**
  39.703 +     * Value of the {@link #AM_PM} field indicating the
  39.704 +     * period of the day from noon to just before midnight.
  39.705 +     */
  39.706 +    public final static int PM = 1;
  39.707 +
  39.708 +    /**
  39.709 +     * A style specifier for {@link #getDisplayNames(int, int, Locale)
  39.710 +     * getDisplayNames} indicating names in all styles, such as
  39.711 +     * "January" and "Jan".
  39.712 +     *
  39.713 +     * @see #SHORT
  39.714 +     * @see #LONG
  39.715 +     * @since 1.6
  39.716 +     */
  39.717 +    public static final int ALL_STYLES = 0;
  39.718 +
  39.719 +    /**
  39.720 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
  39.721 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
  39.722 +     * getDisplayNames} indicating a short name, such as "Jan".
  39.723 +     *
  39.724 +     * @see #LONG
  39.725 +     * @since 1.6
  39.726 +     */
  39.727 +    public static final int SHORT = 1;
  39.728 +
  39.729 +    /**
  39.730 +     * A style specifier for {@link #getDisplayName(int, int, Locale)
  39.731 +     * getDisplayName} and {@link #getDisplayNames(int, int, Locale)
  39.732 +     * getDisplayNames} indicating a long name, such as "January".
  39.733 +     *
  39.734 +     * @see #SHORT
  39.735 +     * @since 1.6
  39.736 +     */
  39.737 +    public static final int LONG = 2;
  39.738 +
  39.739 +    // Internal notes:
  39.740 +    // Calendar contains two kinds of time representations: current "time" in
  39.741 +    // milliseconds, and a set of calendar "fields" representing the current time.
  39.742 +    // The two representations are usually in sync, but can get out of sync
  39.743 +    // as follows.
  39.744 +    // 1. Initially, no fields are set, and the time is invalid.
  39.745 +    // 2. If the time is set, all fields are computed and in sync.
  39.746 +    // 3. If a single field is set, the time is invalid.
  39.747 +    // Recomputation of the time and fields happens when the object needs
  39.748 +    // to return a result to the user, or use a result for a computation.
  39.749 +
  39.750 +    /**
  39.751 +     * The calendar field values for the currently set time for this calendar.
  39.752 +     * This is an array of <code>FIELD_COUNT</code> integers, with index values
  39.753 +     * <code>ERA</code> through <code>DST_OFFSET</code>.
  39.754 +     * @serial
  39.755 +     */
  39.756 +    protected int           fields[];
  39.757 +
  39.758 +    /**
  39.759 +     * The flags which tell if a specified calendar field for the calendar is set.
  39.760 +     * A new object has no fields set.  After the first call to a method
  39.761 +     * which generates the fields, they all remain set after that.
  39.762 +     * This is an array of <code>FIELD_COUNT</code> booleans, with index values
  39.763 +     * <code>ERA</code> through <code>DST_OFFSET</code>.
  39.764 +     * @serial
  39.765 +     */
  39.766 +    protected boolean       isSet[];
  39.767 +
  39.768 +    /**
  39.769 +     * Pseudo-time-stamps which specify when each field was set. There
  39.770 +     * are two special values, UNSET and COMPUTED. Values from
  39.771 +     * MINIMUM_USER_SET to Integer.MAX_VALUE are legal user set values.
  39.772 +     */
  39.773 +    transient private int   stamp[];
  39.774 +
  39.775 +    /**
  39.776 +     * The currently set time for this calendar, expressed in milliseconds after
  39.777 +     * January 1, 1970, 0:00:00 GMT.
  39.778 +     * @see #isTimeSet
  39.779 +     * @serial
  39.780 +     */
  39.781 +    protected long          time;
  39.782 +
  39.783 +    /**
  39.784 +     * True if then the value of <code>time</code> is valid.
  39.785 +     * The time is made invalid by a change to an item of <code>field[]</code>.
  39.786 +     * @see #time
  39.787 +     * @serial
  39.788 +     */
  39.789 +    protected boolean       isTimeSet;
  39.790 +
  39.791 +    /**
  39.792 +     * True if <code>fields[]</code> are in sync with the currently set time.
  39.793 +     * If false, then the next attempt to get the value of a field will
  39.794 +     * force a recomputation of all fields from the current value of
  39.795 +     * <code>time</code>.
  39.796 +     * @serial
  39.797 +     */
  39.798 +    protected boolean       areFieldsSet;
  39.799 +
  39.800 +    /**
  39.801 +     * True if all fields have been set.
  39.802 +     * @serial
  39.803 +     */
  39.804 +    transient boolean       areAllFieldsSet;
  39.805 +
  39.806 +    /**
  39.807 +     * <code>True</code> if this calendar allows out-of-range field values during computation
  39.808 +     * of <code>time</code> from <code>fields[]</code>.
  39.809 +     * @see #setLenient
  39.810 +     * @see #isLenient
  39.811 +     * @serial
  39.812 +     */
  39.813 +    private boolean         lenient = true;
  39.814 +
  39.815 +    /**
  39.816 +     * The <code>TimeZone</code> used by this calendar. <code>Calendar</code>
  39.817 +     * uses the time zone data to translate between locale and GMT time.
  39.818 +     * @serial
  39.819 +     */
  39.820 +    private TimeZone        zone;
  39.821 +
  39.822 +    /**
  39.823 +     * <code>True</code> if zone references to a shared TimeZone object.
  39.824 +     */
  39.825 +    transient private boolean sharedZone = false;
  39.826 +
  39.827 +    /**
  39.828 +     * The first day of the week, with possible values <code>SUNDAY</code>,
  39.829 +     * <code>MONDAY</code>, etc.  This is a locale-dependent value.
  39.830 +     * @serial
  39.831 +     */
  39.832 +    private int             firstDayOfWeek;
  39.833 +
  39.834 +    /**
  39.835 +     * The number of days required for the first week in a month or year,
  39.836 +     * with possible values from 1 to 7.  This is a locale-dependent value.
  39.837 +     * @serial
  39.838 +     */
  39.839 +    private int             minimalDaysInFirstWeek;
  39.840 +
  39.841 +    /**
  39.842 +     * Cache to hold the firstDayOfWeek and minimalDaysInFirstWeek
  39.843 +     * of a Locale.
  39.844 +     */
  39.845 +    private static final ConcurrentMap<Locale, int[]> cachedLocaleData
  39.846 +        = new ConcurrentHashMap<Locale, int[]>(3);
  39.847 +
  39.848 +    // Special values of stamp[]
  39.849 +    /**
  39.850 +     * The corresponding fields[] has no value.
  39.851 +     */
  39.852 +    private static final int        UNSET = 0;
  39.853 +
  39.854 +    /**
  39.855 +     * The value of the corresponding fields[] has been calculated internally.
  39.856 +     */
  39.857 +    private static final int        COMPUTED = 1;
  39.858 +
  39.859 +    /**
  39.860 +     * The value of the corresponding fields[] has been set externally. Stamp
  39.861 +     * values which are greater than 1 represents the (pseudo) time when the
  39.862 +     * corresponding fields[] value was set.
  39.863 +     */
  39.864 +    private static final int        MINIMUM_USER_STAMP = 2;
  39.865 +
  39.866 +    /**
  39.867 +     * The mask value that represents all of the fields.
  39.868 +     */
  39.869 +    static final int ALL_FIELDS = (1 << FIELD_COUNT) - 1;
  39.870 +
  39.871 +    /**
  39.872 +     * The next available value for <code>stamp[]</code>, an internal array.
  39.873 +     * This actually should not be written out to the stream, and will probably
  39.874 +     * be removed from the stream in the near future.  In the meantime,
  39.875 +     * a value of <code>MINIMUM_USER_STAMP</code> should be used.
  39.876 +     * @serial
  39.877 +     */
  39.878 +    private int             nextStamp = MINIMUM_USER_STAMP;
  39.879 +
  39.880 +    // the internal serial version which says which version was written
  39.881 +    // - 0 (default) for version up to JDK 1.1.5
  39.882 +    // - 1 for version from JDK 1.1.6, which writes a correct 'time' value
  39.883 +    //     as well as compatible values for other fields.  This is a
  39.884 +    //     transitional format.
  39.885 +    // - 2 (not implemented yet) a future version, in which fields[],
  39.886 +    //     areFieldsSet, and isTimeSet become transient, and isSet[] is
  39.887 +    //     removed. In JDK 1.1.6 we write a format compatible with version 2.
  39.888 +    static final int        currentSerialVersion = 1;
  39.889 +
  39.890 +    /**
  39.891 +     * The version of the serialized data on the stream.  Possible values:
  39.892 +     * <dl>
  39.893 +     * <dt><b>0</b> or not present on stream</dt>
  39.894 +     * <dd>
  39.895 +     * JDK 1.1.5 or earlier.
  39.896 +     * </dd>
  39.897 +     * <dt><b>1</b></dt>
  39.898 +     * <dd>
  39.899 +     * JDK 1.1.6 or later.  Writes a correct 'time' value
  39.900 +     * as well as compatible values for other fields.  This is a
  39.901 +     * transitional format.
  39.902 +     * </dd>
  39.903 +     * </dl>
  39.904 +     * When streaming out this class, the most recent format
  39.905 +     * and the highest allowable <code>serialVersionOnStream</code>
  39.906 +     * is written.
  39.907 +     * @serial
  39.908 +     * @since JDK1.1.6
  39.909 +     */
  39.910 +    private int             serialVersionOnStream = currentSerialVersion;
  39.911 +
  39.912 +    // Proclaim serialization compatibility with JDK 1.1
  39.913 +    static final long       serialVersionUID = -1807547505821590642L;
  39.914 +
  39.915 +    // Mask values for calendar fields
  39.916 +    final static int ERA_MASK           = (1 << ERA);
  39.917 +    final static int YEAR_MASK          = (1 << YEAR);
  39.918 +    final static int MONTH_MASK         = (1 << MONTH);
  39.919 +    final static int WEEK_OF_YEAR_MASK  = (1 << WEEK_OF_YEAR);
  39.920 +    final static int WEEK_OF_MONTH_MASK = (1 << WEEK_OF_MONTH);
  39.921 +    final static int DAY_OF_MONTH_MASK  = (1 << DAY_OF_MONTH);
  39.922 +    final static int DATE_MASK          = DAY_OF_MONTH_MASK;
  39.923 +    final static int DAY_OF_YEAR_MASK   = (1 << DAY_OF_YEAR);
  39.924 +    final static int DAY_OF_WEEK_MASK   = (1 << DAY_OF_WEEK);
  39.925 +    final static int DAY_OF_WEEK_IN_MONTH_MASK  = (1 << DAY_OF_WEEK_IN_MONTH);
  39.926 +    final static int AM_PM_MASK         = (1 << AM_PM);
  39.927 +    final static int HOUR_MASK          = (1 << HOUR);
  39.928 +    final static int HOUR_OF_DAY_MASK   = (1 << HOUR_OF_DAY);
  39.929 +    final static int MINUTE_MASK        = (1 << MINUTE);
  39.930 +    final static int SECOND_MASK        = (1 << SECOND);
  39.931 +    final static int MILLISECOND_MASK   = (1 << MILLISECOND);
  39.932 +    final static int ZONE_OFFSET_MASK   = (1 << ZONE_OFFSET);
  39.933 +    final static int DST_OFFSET_MASK    = (1 << DST_OFFSET);
  39.934 +
  39.935 +    /**
  39.936 +     * Constructs a Calendar with the default time zone
  39.937 +     * and locale.
  39.938 +     * @see     TimeZone#getDefault
  39.939 +     */
  39.940 +    protected Calendar()
  39.941 +    {
  39.942 +        this(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
  39.943 +        sharedZone = true;
  39.944 +    }
  39.945 +
  39.946 +    /**
  39.947 +     * Constructs a calendar with the specified time zone and locale.
  39.948 +     *
  39.949 +     * @param zone the time zone to use
  39.950 +     * @param aLocale the locale for the week data
  39.951 +     */
  39.952 +    protected Calendar(TimeZone zone, Locale aLocale)
  39.953 +    {
  39.954 +        fields = new int[FIELD_COUNT];
  39.955 +        isSet = new boolean[FIELD_COUNT];
  39.956 +        stamp = new int[FIELD_COUNT];
  39.957 +
  39.958 +        this.zone = zone;
  39.959 +        setWeekCountData(aLocale);
  39.960 +    }
  39.961 +
  39.962 +    /**
  39.963 +     * Gets a calendar using the default time zone and locale. The
  39.964 +     * <code>Calendar</code> returned is based on the current time
  39.965 +     * in the default time zone with the default locale.
  39.966 +     *
  39.967 +     * @return a Calendar.
  39.968 +     */
  39.969 +    public static Calendar getInstance()
  39.970 +    {
  39.971 +        Calendar cal = createCalendar(TimeZone.getDefaultRef(), Locale.getDefault(Locale.Category.FORMAT));
  39.972 +        cal.sharedZone = true;
  39.973 +        return cal;
  39.974 +    }
  39.975 +
  39.976 +    /**
  39.977 +     * Gets a calendar using the specified time zone and default locale.
  39.978 +     * The <code>Calendar</code> returned is based on the current time
  39.979 +     * in the given time zone with the default locale.
  39.980 +     *
  39.981 +     * @param zone the time zone to use
  39.982 +     * @return a Calendar.
  39.983 +     */
  39.984 +    public static Calendar getInstance(TimeZone zone)
  39.985 +    {
  39.986 +        return createCalendar(zone, Locale.getDefault(Locale.Category.FORMAT));
  39.987 +    }
  39.988 +
  39.989 +    /**
  39.990 +     * Gets a calendar using the default time zone and specified locale.
  39.991 +     * The <code>Calendar</code> returned is based on the current time
  39.992 +     * in the default time zone with the given locale.
  39.993 +     *
  39.994 +     * @param aLocale the locale for the week data
  39.995 +     * @return a Calendar.
  39.996 +     */
  39.997 +    public static Calendar getInstance(Locale aLocale)
  39.998 +    {
  39.999 +        Calendar cal = createCalendar(TimeZone.getDefaultRef(), aLocale);
 39.1000 +        cal.sharedZone = true;
 39.1001 +        return cal;
 39.1002 +    }
 39.1003 +
 39.1004 +    /**
 39.1005 +     * Gets a calendar with the specified time zone and locale.
 39.1006 +     * The <code>Calendar</code> returned is based on the current time
 39.1007 +     * in the given time zone with the given locale.
 39.1008 +     *
 39.1009 +     * @param zone the time zone to use
 39.1010 +     * @param aLocale the locale for the week data
 39.1011 +     * @return a Calendar.
 39.1012 +     */
 39.1013 +    public static Calendar getInstance(TimeZone zone,
 39.1014 +                                       Locale aLocale)
 39.1015 +    {
 39.1016 +        return createCalendar(zone, aLocale);
 39.1017 +    }
 39.1018 +
 39.1019 +    private static Calendar createCalendar(TimeZone zone,
 39.1020 +                                           Locale aLocale)
 39.1021 +    {
 39.1022 +        Calendar cal = null;
 39.1023 +
 39.1024 +        String caltype = aLocale.getUnicodeLocaleType("ca");
 39.1025 +        if (caltype == null) {
 39.1026 +            // Calendar type is not specified.
 39.1027 +            // If the specified locale is a Thai locale,
 39.1028 +            // returns a BuddhistCalendar instance.
 39.1029 +            if ("th".equals(aLocale.getLanguage())
 39.1030 +                    && ("TH".equals(aLocale.getCountry()))) {
 39.1031 +                cal = new BuddhistCalendar(zone, aLocale);
 39.1032 +            } else {
 39.1033 +                cal = new GregorianCalendar(zone, aLocale);
 39.1034 +            }
 39.1035 +        } else if (caltype.equals("japanese")) {
 39.1036 +            cal = new JapaneseImperialCalendar(zone, aLocale);
 39.1037 +        } else if (caltype.equals("buddhist")) {
 39.1038 +            cal = new BuddhistCalendar(zone, aLocale);
 39.1039 +        } else {
 39.1040 +            // Unsupported calendar type.
 39.1041 +            // Use Gregorian calendar as a fallback.
 39.1042 +            cal = new GregorianCalendar(zone, aLocale);
 39.1043 +        }
 39.1044 +
 39.1045 +        return cal;
 39.1046 +    }
 39.1047 +
 39.1048 +    /**
 39.1049 +     * Returns an array of all locales for which the <code>getInstance</code>
 39.1050 +     * methods of this class can return localized instances.
 39.1051 +     * The array returned must contain at least a <code>Locale</code>
 39.1052 +     * instance equal to {@link java.util.Locale#US Locale.US}.
 39.1053 +     *
 39.1054 +     * @return An array of locales for which localized
 39.1055 +     *         <code>Calendar</code> instances are available.
 39.1056 +     */
 39.1057 +    public static synchronized Locale[] getAvailableLocales()
 39.1058 +    {
 39.1059 +        return DateFormat.getAvailableLocales();
 39.1060 +    }
 39.1061 +
 39.1062 +    /**
 39.1063 +     * Converts the current calendar field values in {@link #fields fields[]}
 39.1064 +     * to the millisecond time value
 39.1065 +     * {@link #time}.
 39.1066 +     *
 39.1067 +     * @see #complete()
 39.1068 +     * @see #computeFields()
 39.1069 +     */
 39.1070 +    protected abstract void computeTime();
 39.1071 +
 39.1072 +    /**
 39.1073 +     * Converts the current millisecond time value {@link #time}
 39.1074 +     * to calendar field values in {@link #fields fields[]}.
 39.1075 +     * This allows you to sync up the calendar field values with
 39.1076 +     * a new time that is set for the calendar.  The time is <em>not</em>
 39.1077 +     * recomputed first; to recompute the time, then the fields, call the
 39.1078 +     * {@link #complete()} method.
 39.1079 +     *
 39.1080 +     * @see #computeTime()
 39.1081 +     */
 39.1082 +    protected abstract void computeFields();
 39.1083 +
 39.1084 +    /**
 39.1085 +     * Returns a <code>Date</code> object representing this
 39.1086 +     * <code>Calendar</code>'s time value (millisecond offset from the <a
 39.1087 +     * href="#Epoch">Epoch</a>").
 39.1088 +     *
 39.1089 +     * @return a <code>Date</code> representing the time value.
 39.1090 +     * @see #setTime(Date)
 39.1091 +     * @see #getTimeInMillis()
 39.1092 +     */
 39.1093 +    public final Date getTime() {
 39.1094 +        return new Date(getTimeInMillis());
 39.1095 +    }
 39.1096 +
 39.1097 +    /**
 39.1098 +     * Sets this Calendar's time with the given <code>Date</code>.
 39.1099 +     * <p>
 39.1100 +     * Note: Calling <code>setTime()</code> with
 39.1101 +     * <code>Date(Long.MAX_VALUE)</code> or <code>Date(Long.MIN_VALUE)</code>
 39.1102 +     * may yield incorrect field values from <code>get()</code>.
 39.1103 +     *
 39.1104 +     * @param date the given Date.
 39.1105 +     * @see #getTime()
 39.1106 +     * @see #setTimeInMillis(long)
 39.1107 +     */
 39.1108 +    public final void setTime(Date date) {
 39.1109 +        setTimeInMillis(date.getTime());
 39.1110 +    }
 39.1111 +
 39.1112 +    /**
 39.1113 +     * Returns this Calendar's time value in milliseconds.
 39.1114 +     *
 39.1115 +     * @return the current time as UTC milliseconds from the epoch.
 39.1116 +     * @see #getTime()
 39.1117 +     * @see #setTimeInMillis(long)
 39.1118 +     */
 39.1119 +    public long getTimeInMillis() {
 39.1120 +        if (!isTimeSet) {
 39.1121 +            updateTime();
 39.1122 +        }
 39.1123 +        return time;
 39.1124 +    }
 39.1125 +
 39.1126 +    /**
 39.1127 +     * Sets this Calendar's current time from the given long value.
 39.1128 +     *
 39.1129 +     * @param millis the new time in UTC milliseconds from the epoch.
 39.1130 +     * @see #setTime(Date)
 39.1131 +     * @see #getTimeInMillis()
 39.1132 +     */
 39.1133 +    public void setTimeInMillis(long millis) {
 39.1134 +        // If we don't need to recalculate the calendar field values,
 39.1135 +        // do nothing.
 39.1136 +        if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
 39.1137 +            && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
 39.1138 +            return;
 39.1139 +        }
 39.1140 +        time = millis;
 39.1141 +        isTimeSet = true;
 39.1142 +        areFieldsSet = false;
 39.1143 +        computeFields();
 39.1144 +        areAllFieldsSet = areFieldsSet = true;
 39.1145 +    }
 39.1146 +
 39.1147 +    /**
 39.1148 +     * Returns the value of the given calendar field. In lenient mode,
 39.1149 +     * all calendar fields are normalized. In non-lenient mode, all
 39.1150 +     * calendar fields are validated and this method throws an
 39.1151 +     * exception if any calendar fields have out-of-range values. The
 39.1152 +     * normalization and validation are handled by the
 39.1153 +     * {@link #complete()} method, which process is calendar
 39.1154 +     * system dependent.
 39.1155 +     *
 39.1156 +     * @param field the given calendar field.
 39.1157 +     * @return the value for the given calendar field.
 39.1158 +     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
 39.1159 +     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
 39.1160 +     * @see #set(int,int)
 39.1161 +     * @see #complete()
 39.1162 +     */
 39.1163 +    public int get(int field)
 39.1164 +    {
 39.1165 +        complete();
 39.1166 +        return internalGet(field);
 39.1167 +    }
 39.1168 +
 39.1169 +    /**
 39.1170 +     * Returns the value of the given calendar field. This method does
 39.1171 +     * not involve normalization or validation of the field value.
 39.1172 +     *
 39.1173 +     * @param field the given calendar field.
 39.1174 +     * @return the value for the given calendar field.
 39.1175 +     * @see #get(int)
 39.1176 +     */
 39.1177 +    protected final int internalGet(int field)
 39.1178 +    {
 39.1179 +        return fields[field];
 39.1180 +    }
 39.1181 +
 39.1182 +    /**
 39.1183 +     * Sets the value of the given calendar field. This method does
 39.1184 +     * not affect any setting state of the field in this
 39.1185 +     * <code>Calendar</code> instance.
 39.1186 +     *
 39.1187 +     * @throws IndexOutOfBoundsException if the specified field is out of range
 39.1188 +     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
 39.1189 +     * @see #areFieldsSet
 39.1190 +     * @see #isTimeSet
 39.1191 +     * @see #areAllFieldsSet
 39.1192 +     * @see #set(int,int)
 39.1193 +     */
 39.1194 +    final void internalSet(int field, int value)
 39.1195 +    {
 39.1196 +        fields[field] = value;
 39.1197 +    }
 39.1198 +
 39.1199 +    /**
 39.1200 +     * Sets the given calendar field to the given value. The value is not
 39.1201 +     * interpreted by this method regardless of the leniency mode.
 39.1202 +     *
 39.1203 +     * @param field the given calendar field.
 39.1204 +     * @param value the value to be set for the given calendar field.
 39.1205 +     * @throws ArrayIndexOutOfBoundsException if the specified field is out of range
 39.1206 +     *             (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
 39.1207 +     * in non-lenient mode.
 39.1208 +     * @see #set(int,int,int)
 39.1209 +     * @see #set(int,int,int,int,int)
 39.1210 +     * @see #set(int,int,int,int,int,int)
 39.1211 +     * @see #get(int)
 39.1212 +     */
 39.1213 +    public void set(int field, int value)
 39.1214 +    {
 39.1215 +        // If the fields are partially normalized, calculate all the
 39.1216 +        // fields before changing any fields.
 39.1217 +        if (areFieldsSet && !areAllFieldsSet) {
 39.1218 +            computeFields();
 39.1219 +        }
 39.1220 +        internalSet(field, value);
 39.1221 +        isTimeSet = false;
 39.1222 +        areFieldsSet = false;
 39.1223 +        isSet[field] = true;
 39.1224 +        stamp[field] = nextStamp++;
 39.1225 +        if (nextStamp == Integer.MAX_VALUE) {
 39.1226 +            adjustStamp();
 39.1227 +        }
 39.1228 +    }
 39.1229 +
 39.1230 +    /**
 39.1231 +     * Sets the values for the calendar fields <code>YEAR</code>,
 39.1232 +     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code>.
 39.1233 +     * Previous values of other calendar fields are retained.  If this is not desired,
 39.1234 +     * call {@link #clear()} first.
 39.1235 +     *
 39.1236 +     * @param year the value used to set the <code>YEAR</code> calendar field.
 39.1237 +     * @param month the value used to set the <code>MONTH</code> calendar field.
 39.1238 +     * Month value is 0-based. e.g., 0 for January.
 39.1239 +     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
 39.1240 +     * @see #set(int,int)
 39.1241 +     * @see #set(int,int,int,int,int)
 39.1242 +     * @see #set(int,int,int,int,int,int)
 39.1243 +     */
 39.1244 +    public final void set(int year, int month, int date)
 39.1245 +    {
 39.1246 +        set(YEAR, year);
 39.1247 +        set(MONTH, month);
 39.1248 +        set(DATE, date);
 39.1249 +    }
 39.1250 +
 39.1251 +    /**
 39.1252 +     * Sets the values for the calendar fields <code>YEAR</code>,
 39.1253 +     * <code>MONTH</code>, <code>DAY_OF_MONTH</code>,
 39.1254 +     * <code>HOUR_OF_DAY</code>, and <code>MINUTE</code>.
 39.1255 +     * Previous values of other fields are retained.  If this is not desired,
 39.1256 +     * call {@link #clear()} first.
 39.1257 +     *
 39.1258 +     * @param year the value used to set the <code>YEAR</code> calendar field.
 39.1259 +     * @param month the value used to set the <code>MONTH</code> calendar field.
 39.1260 +     * Month value is 0-based. e.g., 0 for January.
 39.1261 +     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
 39.1262 +     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
 39.1263 +     * @param minute the value used to set the <code>MINUTE</code> calendar field.
 39.1264 +     * @see #set(int,int)
 39.1265 +     * @see #set(int,int,int)
 39.1266 +     * @see #set(int,int,int,int,int,int)
 39.1267 +     */
 39.1268 +    public final void set(int year, int month, int date, int hourOfDay, int minute)
 39.1269 +    {
 39.1270 +        set(YEAR, year);
 39.1271 +        set(MONTH, month);
 39.1272 +        set(DATE, date);
 39.1273 +        set(HOUR_OF_DAY, hourOfDay);
 39.1274 +        set(MINUTE, minute);
 39.1275 +    }
 39.1276 +
 39.1277 +    /**
 39.1278 +     * Sets the values for the fields <code>YEAR</code>, <code>MONTH</code>,
 39.1279 +     * <code>DAY_OF_MONTH</code>, <code>HOUR</code>, <code>MINUTE</code>, and
 39.1280 +     * <code>SECOND</code>.
 39.1281 +     * Previous values of other fields are retained.  If this is not desired,
 39.1282 +     * call {@link #clear()} first.
 39.1283 +     *
 39.1284 +     * @param year the value used to set the <code>YEAR</code> calendar field.
 39.1285 +     * @param month the value used to set the <code>MONTH</code> calendar field.
 39.1286 +     * Month value is 0-based. e.g., 0 for January.
 39.1287 +     * @param date the value used to set the <code>DAY_OF_MONTH</code> calendar field.
 39.1288 +     * @param hourOfDay the value used to set the <code>HOUR_OF_DAY</code> calendar field.
 39.1289 +     * @param minute the value used to set the <code>MINUTE</code> calendar field.
 39.1290 +     * @param second the value used to set the <code>SECOND</code> calendar field.
 39.1291 +     * @see #set(int,int)
 39.1292 +     * @see #set(int,int,int)
 39.1293 +     * @see #set(int,int,int,int,int)
 39.1294 +     */
 39.1295 +    public final void set(int year, int month, int date, int hourOfDay, int minute,
 39.1296 +                          int second)
 39.1297 +    {
 39.1298 +        set(YEAR, year);
 39.1299 +        set(MONTH, month);
 39.1300 +        set(DATE, date);
 39.1301 +        set(HOUR_OF_DAY, hourOfDay);
 39.1302 +        set(MINUTE, minute);
 39.1303 +        set(SECOND, second);
 39.1304 +    }
 39.1305 +
 39.1306 +    /**
 39.1307 +     * Sets all the calendar field values and the time value
 39.1308 +     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
 39.1309 +     * this <code>Calendar</code> undefined. This means that {@link
 39.1310 +     * #isSet(int) isSet()} will return <code>false</code> for all the
 39.1311 +     * calendar fields, and the date and time calculations will treat
 39.1312 +     * the fields as if they had never been set. A
 39.1313 +     * <code>Calendar</code> implementation class may use its specific
 39.1314 +     * default field values for date/time calculations. For example,
 39.1315 +     * <code>GregorianCalendar</code> uses 1970 if the
 39.1316 +     * <code>YEAR</code> field value is undefined.
 39.1317 +     *
 39.1318 +     * @see #clear(int)
 39.1319 +     */
 39.1320 +    public final void clear()
 39.1321 +    {
 39.1322 +        for (int i = 0; i < fields.length; ) {
 39.1323 +            stamp[i] = fields[i] = 0; // UNSET == 0
 39.1324 +            isSet[i++] = false;
 39.1325 +        }
 39.1326 +        areAllFieldsSet = areFieldsSet = false;
 39.1327 +        isTimeSet = false;
 39.1328 +    }
 39.1329 +
 39.1330 +    /**
 39.1331 +     * Sets the given calendar field value and the time value
 39.1332 +     * (millisecond offset from the <a href="#Epoch">Epoch</a>) of
 39.1333 +     * this <code>Calendar</code> undefined. This means that {@link
 39.1334 +     * #isSet(int) isSet(field)} will return <code>false</code>, and
 39.1335 +     * the date and time calculations will treat the field as if it
 39.1336 +     * had never been set. A <code>Calendar</code> implementation
 39.1337 +     * class may use the field's specific default value for date and
 39.1338 +     * time calculations.
 39.1339 +     *
 39.1340 +     * <p>The {@link #HOUR_OF_DAY}, {@link #HOUR} and {@link #AM_PM}
 39.1341 +     * fields are handled independently and the <a
 39.1342 +     * href="#time_resolution">the resolution rule for the time of
 39.1343 +     * day</a> is applied. Clearing one of the fields doesn't reset
 39.1344 +     * the hour of day value of this <code>Calendar</code>. Use {@link
 39.1345 +     * #set(int,int) set(Calendar.HOUR_OF_DAY, 0)} to reset the hour
 39.1346 +     * value.
 39.1347 +     *
 39.1348 +     * @param field the calendar field to be cleared.
 39.1349 +     * @see #clear()
 39.1350 +     */
 39.1351 +    public final void clear(int field)
 39.1352 +    {
 39.1353 +        fields[field] = 0;
 39.1354 +        stamp[field] = UNSET;
 39.1355 +        isSet[field] = false;
 39.1356 +
 39.1357 +        areAllFieldsSet = areFieldsSet = false;
 39.1358 +        isTimeSet = false;
 39.1359 +    }
 39.1360 +
 39.1361 +    /**
 39.1362 +     * Determines if the given calendar field has a value set,
 39.1363 +     * including cases that the value has been set by internal fields
 39.1364 +     * calculations triggered by a <code>get</code> method call.
 39.1365 +     *
 39.1366 +     * @return <code>true</code> if the given calendar field has a value set;
 39.1367 +     * <code>false</code> otherwise.
 39.1368 +     */
 39.1369 +    public final boolean isSet(int field)
 39.1370 +    {
 39.1371 +        return stamp[field] != UNSET;
 39.1372 +    }
 39.1373 +
 39.1374 +    /**
 39.1375 +     * Returns the string representation of the calendar
 39.1376 +     * <code>field</code> value in the given <code>style</code> and
 39.1377 +     * <code>locale</code>.  If no string representation is
 39.1378 +     * applicable, <code>null</code> is returned. This method calls
 39.1379 +     * {@link Calendar#get(int) get(field)} to get the calendar
 39.1380 +     * <code>field</code> value if the string representation is
 39.1381 +     * applicable to the given calendar <code>field</code>.
 39.1382 +     *
 39.1383 +     * <p>For example, if this <code>Calendar</code> is a
 39.1384 +     * <code>GregorianCalendar</code> and its date is 2005-01-01, then
 39.1385 +     * the string representation of the {@link #MONTH} field would be
 39.1386 +     * "January" in the long style in an English locale or "Jan" in
 39.1387 +     * the short style. However, no string representation would be
 39.1388 +     * available for the {@link #DAY_OF_MONTH} field, and this method
 39.1389 +     * would return <code>null</code>.
 39.1390 +     *
 39.1391 +     * <p>The default implementation supports the calendar fields for
 39.1392 +     * which a {@link DateFormatSymbols} has names in the given
 39.1393 +     * <code>locale</code>.
 39.1394 +     *
 39.1395 +     * @param field
 39.1396 +     *        the calendar field for which the string representation
 39.1397 +     *        is returned
 39.1398 +     * @param style
 39.1399 +     *        the style applied to the string representation; one of
 39.1400 +     *        {@link #SHORT} or {@link #LONG}.
 39.1401 +     * @param locale
 39.1402 +     *        the locale for the string representation
 39.1403 +     * @return the string representation of the given
 39.1404 +     *        <code>field</code> in the given <code>style</code>, or
 39.1405 +     *        <code>null</code> if no string representation is
 39.1406 +     *        applicable.
 39.1407 +     * @exception IllegalArgumentException
 39.1408 +     *        if <code>field</code> or <code>style</code> is invalid,
 39.1409 +     *        or if this <code>Calendar</code> is non-lenient and any
 39.1410 +     *        of the calendar fields have invalid values
 39.1411 +     * @exception NullPointerException
 39.1412 +     *        if <code>locale</code> is null
 39.1413 +     * @since 1.6
 39.1414 +     */
 39.1415 +    public String getDisplayName(int field, int style, Locale locale) {
 39.1416 +        if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
 39.1417 +                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
 39.1418 +            return null;
 39.1419 +        }
 39.1420 +
 39.1421 +        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
 39.1422 +        String[] strings = getFieldStrings(field, style, symbols);
 39.1423 +        if (strings != null) {
 39.1424 +            int fieldValue = get(field);
 39.1425 +            if (fieldValue < strings.length) {
 39.1426 +                return strings[fieldValue];
 39.1427 +            }
 39.1428 +        }
 39.1429 +        return null;
 39.1430 +    }
 39.1431 +
 39.1432 +    /**
 39.1433 +     * Returns a <code>Map</code> containing all names of the calendar
 39.1434 +     * <code>field</code> in the given <code>style</code> and
 39.1435 +     * <code>locale</code> and their corresponding field values. For
 39.1436 +     * example, if this <code>Calendar</code> is a {@link
 39.1437 +     * GregorianCalendar}, the returned map would contain "Jan" to
 39.1438 +     * {@link #JANUARY}, "Feb" to {@link #FEBRUARY}, and so on, in the
 39.1439 +     * {@linkplain #SHORT short} style in an English locale.
 39.1440 +     *
 39.1441 +     * <p>The values of other calendar fields may be taken into
 39.1442 +     * account to determine a set of display names. For example, if
 39.1443 +     * this <code>Calendar</code> is a lunisolar calendar system and
 39.1444 +     * the year value given by the {@link #YEAR} field has a leap
 39.1445 +     * month, this method would return month names containing the leap
 39.1446 +     * month name, and month names are mapped to their values specific
 39.1447 +     * for the year.
 39.1448 +     *
 39.1449 +     * <p>The default implementation supports display names contained in
 39.1450 +     * a {@link DateFormatSymbols}. For example, if <code>field</code>
 39.1451 +     * is {@link #MONTH} and <code>style</code> is {@link
 39.1452 +     * #ALL_STYLES}, this method returns a <code>Map</code> containing
 39.1453 +     * all strings returned by {@link DateFormatSymbols#getShortMonths()}
 39.1454 +     * and {@link DateFormatSymbols#getMonths()}.
 39.1455 +     *
 39.1456 +     * @param field
 39.1457 +     *        the calendar field for which the display names are returned
 39.1458 +     * @param style
 39.1459 +     *        the style applied to the display names; one of {@link
 39.1460 +     *        #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}.
 39.1461 +     * @param locale
 39.1462 +     *        the locale for the display names
 39.1463 +     * @return a <code>Map</code> containing all display names in
 39.1464 +     *        <code>style</code> and <code>locale</code> and their
 39.1465 +     *        field values, or <code>null</code> if no display names
 39.1466 +     *        are defined for <code>field</code>
 39.1467 +     * @exception IllegalArgumentException
 39.1468 +     *        if <code>field</code> or <code>style</code> is invalid,
 39.1469 +     *        or if this <code>Calendar</code> is non-lenient and any
 39.1470 +     *        of the calendar fields have invalid values
 39.1471 +     * @exception NullPointerException
 39.1472 +     *        if <code>locale</code> is null
 39.1473 +     * @since 1.6
 39.1474 +     */
 39.1475 +    public Map<String, Integer> getDisplayNames(int field, int style, Locale locale) {
 39.1476 +        if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale,
 39.1477 +                                    ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
 39.1478 +            return null;
 39.1479 +        }
 39.1480 +
 39.1481 +        // ALL_STYLES
 39.1482 +        if (style == ALL_STYLES) {
 39.1483 +            Map<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
 39.1484 +            if (field == ERA || field == AM_PM) {
 39.1485 +                return shortNames;
 39.1486 +            }
 39.1487 +            Map<String,Integer> longNames = getDisplayNamesImpl(field, LONG, locale);
 39.1488 +            if (shortNames == null) {
 39.1489 +                return longNames;
 39.1490 +            }
 39.1491 +            if (longNames != null) {
 39.1492 +                shortNames.putAll(longNames);
 39.1493 +            }
 39.1494 +            return shortNames;
 39.1495 +        }
 39.1496 +
 39.1497 +        // SHORT or LONG
 39.1498 +        return getDisplayNamesImpl(field, style, locale);
 39.1499 +    }
 39.1500 +
 39.1501 +    private Map<String,Integer> getDisplayNamesImpl(int field, int style, Locale locale) {
 39.1502 +        DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
 39.1503 +        String[] strings = getFieldStrings(field, style, symbols);
 39.1504 +        if (strings != null) {
 39.1505 +            Map<String,Integer> names = new HashMap<String,Integer>();
 39.1506 +            for (int i = 0; i < strings.length; i++) {
 39.1507 +                if (strings[i].length() == 0) {
 39.1508 +                    continue;
 39.1509 +                }
 39.1510 +                names.put(strings[i], i);
 39.1511 +            }
 39.1512 +            return names;
 39.1513 +        }
 39.1514 +        return null;
 39.1515 +    }
 39.1516 +
 39.1517 +    boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle,
 39.1518 +                                   Locale locale, int fieldMask) {
 39.1519 +        if (field < 0 || field >= fields.length ||
 39.1520 +            style < minStyle || style > maxStyle) {
 39.1521 +            throw new IllegalArgumentException();
 39.1522 +        }
 39.1523 +        if (locale == null) {
 39.1524 +            throw new NullPointerException();
 39.1525 +        }
 39.1526 +        return isFieldSet(fieldMask, field);
 39.1527 +    }
 39.1528 +
 39.1529 +    private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) {
 39.1530 +        String[] strings = null;
 39.1531 +        switch (field) {
 39.1532 +        case ERA:
 39.1533 +            strings = symbols.getEras();
 39.1534 +            break;
 39.1535 +
 39.1536 +        case MONTH:
 39.1537 +            strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths();
 39.1538 +            break;
 39.1539 +
 39.1540 +        case DAY_OF_WEEK:
 39.1541 +            strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays();
 39.1542 +            break;
 39.1543 +
 39.1544 +        case AM_PM:
 39.1545 +            strings = symbols.getAmPmStrings();
 39.1546 +            break;
 39.1547 +        }
 39.1548 +        return strings;
 39.1549 +    }
 39.1550 +
 39.1551 +    /**
 39.1552 +     * Fills in any unset fields in the calendar fields. First, the {@link
 39.1553 +     * #computeTime()} method is called if the time value (millisecond offset
 39.1554 +     * from the <a href="#Epoch">Epoch</a>) has not been calculated from
 39.1555 +     * calendar field values. Then, the {@link #computeFields()} method is
 39.1556 +     * called to calculate all calendar field values.
 39.1557 +     */
 39.1558 +    protected void complete()
 39.1559 +    {
 39.1560 +        if (!isTimeSet)
 39.1561 +            updateTime();
 39.1562 +        if (!areFieldsSet || !areAllFieldsSet) {
 39.1563 +            computeFields(); // fills in unset fields
 39.1564 +            areAllFieldsSet = areFieldsSet = true;
 39.1565 +        }
 39.1566 +    }
 39.1567 +
 39.1568 +    /**
 39.1569 +     * Returns whether the value of the specified calendar field has been set
 39.1570 +     * externally by calling one of the setter methods rather than by the
 39.1571 +     * internal time calculation.
 39.1572 +     *
 39.1573 +     * @return <code>true</code> if the field has been set externally,
 39.1574 +     * <code>false</code> otherwise.
 39.1575 +     * @exception IndexOutOfBoundsException if the specified
 39.1576 +     *                <code>field</code> is out of range
 39.1577 +     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
 39.1578 +     * @see #selectFields()
 39.1579 +     * @see #setFieldsComputed(int)
 39.1580 +     */
 39.1581 +    final boolean isExternallySet(int field) {
 39.1582 +        return stamp[field] >= MINIMUM_USER_STAMP;
 39.1583 +    }
 39.1584 +
 39.1585 +    /**
 39.1586 +     * Returns a field mask (bit mask) indicating all calendar fields that
 39.1587 +     * have the state of externally or internally set.
 39.1588 +     *
 39.1589 +     * @return a bit mask indicating set state fields
 39.1590 +     */
 39.1591 +    final int getSetStateFields() {
 39.1592 +        int mask = 0;
 39.1593 +        for (int i = 0; i < fields.length; i++) {
 39.1594 +            if (stamp[i] != UNSET) {
 39.1595 +                mask |= 1 << i;
 39.1596 +            }
 39.1597 +        }
 39.1598 +        return mask;
 39.1599 +    }
 39.1600 +
 39.1601 +    /**
 39.1602 +     * Sets the state of the specified calendar fields to
 39.1603 +     * <em>computed</em>. This state means that the specified calendar fields
 39.1604 +     * have valid values that have been set by internal time calculation
 39.1605 +     * rather than by calling one of the setter methods.
 39.1606 +     *
 39.1607 +     * @param fieldMask the field to be marked as computed.
 39.1608 +     * @exception IndexOutOfBoundsException if the specified
 39.1609 +     *                <code>field</code> is out of range
 39.1610 +     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
 39.1611 +     * @see #isExternallySet(int)
 39.1612 +     * @see #selectFields()
 39.1613 +     */
 39.1614 +    final void setFieldsComputed(int fieldMask) {
 39.1615 +        if (fieldMask == ALL_FIELDS) {
 39.1616 +            for (int i = 0; i < fields.length; i++) {
 39.1617 +                stamp[i] = COMPUTED;
 39.1618 +                isSet[i] = true;
 39.1619 +            }
 39.1620 +            areFieldsSet = areAllFieldsSet = true;
 39.1621 +        } else {
 39.1622 +            for (int i = 0; i < fields.length; i++) {
 39.1623 +                if ((fieldMask & 1) == 1) {
 39.1624 +                    stamp[i] = COMPUTED;
 39.1625 +                    isSet[i] = true;
 39.1626 +                } else {
 39.1627 +                    if (areAllFieldsSet && !isSet[i]) {
 39.1628 +                        areAllFieldsSet = false;
 39.1629 +                    }
 39.1630 +                }
 39.1631 +                fieldMask >>>= 1;
 39.1632 +            }
 39.1633 +        }
 39.1634 +    }
 39.1635 +
 39.1636 +    /**
 39.1637 +     * Sets the state of the calendar fields that are <em>not</em> specified
 39.1638 +     * by <code>fieldMask</code> to <em>unset</em>. If <code>fieldMask</code>
 39.1639 +     * specifies all the calendar fields, then the state of this
 39.1640 +     * <code>Calendar</code> becomes that all the calendar fields are in sync
 39.1641 +     * with the time value (millisecond offset from the Epoch).
 39.1642 +     *
 39.1643 +     * @param fieldMask the field mask indicating which calendar fields are in
 39.1644 +     * sync with the time value.
 39.1645 +     * @exception IndexOutOfBoundsException if the specified
 39.1646 +     *                <code>field</code> is out of range
 39.1647 +     *               (<code>field &lt; 0 || field &gt;= FIELD_COUNT</code>).
 39.1648 +     * @see #isExternallySet(int)
 39.1649 +     * @see #selectFields()
 39.1650 +     */
 39.1651 +    final void setFieldsNormalized(int fieldMask) {
 39.1652 +        if (fieldMask != ALL_FIELDS) {
 39.1653 +            for (int i = 0; i < fields.length; i++) {
 39.1654 +                if ((fieldMask & 1) == 0) {
 39.1655 +                    stamp[i] = fields[i] = 0; // UNSET == 0
 39.1656 +                    isSet[i] = false;
 39.1657 +                }
 39.1658 +                fieldMask >>= 1;
 39.1659 +            }
 39.1660 +        }
 39.1661 +
 39.1662 +        // Some or all of the fields are in sync with the
 39.1663 +        // milliseconds, but the stamp values are not normalized yet.
 39.1664 +        areFieldsSet = true;
 39.1665 +        areAllFieldsSet = false;
 39.1666 +    }
 39.1667 +
 39.1668 +    /**
 39.1669 +     * Returns whether the calendar fields are partially in sync with the time
 39.1670 +     * value or fully in sync but not stamp values are not normalized yet.
 39.1671 +     */
 39.1672 +    final boolean isPartiallyNormalized() {
 39.1673 +        return areFieldsSet && !areAllFieldsSet;
 39.1674 +    }
 39.1675 +
 39.1676 +    /**
 39.1677 +     * Returns whether the calendar fields are fully in sync with the time
 39.1678 +     * value.
 39.1679 +     */
 39.1680 +    final boolean isFullyNormalized() {
 39.1681 +        return areFieldsSet && areAllFieldsSet;
 39.1682 +    }
 39.1683 +
 39.1684 +    /**
 39.1685 +     * Marks this Calendar as not sync'd.
 39.1686 +     */
 39.1687 +    final void setUnnormalized() {
 39.1688 +        areFieldsSet = areAllFieldsSet = false;
 39.1689 +    }
 39.1690 +
 39.1691 +    /**
 39.1692 +     * Returns whether the specified <code>field</code> is on in the
 39.1693 +     * <code>fieldMask</code>.
 39.1694 +     */
 39.1695 +    static final boolean isFieldSet(int fieldMask, int field) {
 39.1696 +        return (fieldMask & (1 << field)) != 0;
 39.1697 +    }
 39.1698 +
 39.1699 +    /**
 39.1700 +     * Returns a field mask indicating which calendar field values
 39.1701 +     * to be used to calculate the time value. The calendar fields are
 39.1702 +     * returned as a bit mask, each bit of which corresponds to a field, i.e.,
 39.1703 +     * the mask value of <code>field</code> is <code>(1 &lt;&lt;
 39.1704 +     * field)</code>. For example, 0x26 represents the <code>YEAR</code>,
 39.1705 +     * <code>MONTH</code>, and <code>DAY_OF_MONTH</code> fields (i.e., 0x26 is
 39.1706 +     * equal to
 39.1707 +     * <code>(1&lt;&lt;YEAR)|(1&lt;&lt;MONTH)|(1&lt;&lt;DAY_OF_MONTH))</code>.
 39.1708 +     *
 39.1709 +     * <p>This method supports the calendar fields resolution as described in
 39.1710 +     * the class description. If the bit mask for a given field is on and its
 39.1711 +     * field has not been set (i.e., <code>isSet(field)</code> is
 39.1712 +     * <code>false</code>), then the default value of the field has to be
 39.1713 +     * used, which case means that the field has been selected because the
 39.1714 +     * selected combination involves the field.
 39.1715 +     *
 39.1716 +     * @return a bit mask of selected fields
 39.1717 +     * @see #isExternallySet(int)
 39.1718 +     * @see #setInternallySetState(int)
 39.1719 +     */
 39.1720 +    final int selectFields() {
 39.1721 +        // This implementation has been taken from the GregorianCalendar class.
 39.1722 +
 39.1723 +        // The YEAR field must always be used regardless of its SET
 39.1724 +        // state because YEAR is a mandatory field to determine the date
 39.1725 +        // and the default value (EPOCH_YEAR) may change through the
 39.1726 +        // normalization process.
 39.1727 +        int fieldMask = YEAR_MASK;
 39.1728 +
 39.1729 +        if (stamp[ERA] != UNSET) {
 39.1730 +            fieldMask |= ERA_MASK;
 39.1731 +        }
 39.1732 +        // Find the most recent group of fields specifying the day within
 39.1733 +        // the year.  These may be any of the following combinations:
 39.1734 +        //   MONTH + DAY_OF_MONTH
 39.1735 +        //   MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
 39.1736 +        //   MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
 39.1737 +        //   DAY_OF_YEAR
 39.1738 +        //   WEEK_OF_YEAR + DAY_OF_WEEK
 39.1739 +        // We look for the most recent of the fields in each group to determine
 39.1740 +        // the age of the group.  For groups involving a week-related field such
 39.1741 +        // as WEEK_OF_MONTH, DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR, both the
 39.1742 +        // week-related field and the DAY_OF_WEEK must be set for the group as a
 39.1743 +        // whole to be considered.  (See bug 4153860 - liu 7/24/98.)
 39.1744 +        int dowStamp = stamp[DAY_OF_WEEK];
 39.1745 +        int monthStamp = stamp[MONTH];
 39.1746 +        int domStamp = stamp[DAY_OF_MONTH];
 39.1747 +        int womStamp = aggregateStamp(stamp[WEEK_OF_MONTH], dowStamp);
 39.1748 +        int dowimStamp = aggregateStamp(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
 39.1749 +        int doyStamp = stamp[DAY_OF_YEAR];
 39.1750 +        int woyStamp = aggregateStamp(stamp[WEEK_OF_YEAR], dowStamp);
 39.1751 +
 39.1752 +        int bestStamp = domStamp;
 39.1753 +        if (womStamp > bestStamp) {
 39.1754 +            bestStamp = womStamp;
 39.1755 +        }
 39.1756 +        if (dowimStamp > bestStamp) {
 39.1757 +            bestStamp = dowimStamp;
 39.1758 +        }
 39.1759 +        if (doyStamp > bestStamp) {
 39.1760 +            bestStamp = doyStamp;
 39.1761 +        }
 39.1762 +        if (woyStamp > bestStamp) {
 39.1763 +            bestStamp = woyStamp;
 39.1764 +        }
 39.1765 +
 39.1766 +        /* No complete combination exists.  Look for WEEK_OF_MONTH,
 39.1767 +         * DAY_OF_WEEK_IN_MONTH, or WEEK_OF_YEAR alone.  Treat DAY_OF_WEEK alone
 39.1768 +         * as DAY_OF_WEEK_IN_MONTH.
 39.1769 +         */
 39.1770 +        if (bestStamp == UNSET) {
 39.1771 +            womStamp = stamp[WEEK_OF_MONTH];
 39.1772 +            dowimStamp = Math.max(stamp[DAY_OF_WEEK_IN_MONTH], dowStamp);
 39.1773 +            woyStamp = stamp[WEEK_OF_YEAR];
 39.1774 +            bestStamp = Math.max(Math.max(womStamp, dowimStamp), woyStamp);
 39.1775 +
 39.1776 +            /* Treat MONTH alone or no fields at all as DAY_OF_MONTH.  This may
 39.1777 +             * result in bestStamp = domStamp = UNSET if no fields are set,
 39.1778 +             * which indicates DAY_OF_MONTH.
 39.1779 +             */
 39.1780 +            if (bestStamp == UNSET) {
 39.1781 +                bestStamp = domStamp = monthStamp;
 39.1782 +            }
 39.1783 +        }
 39.1784 +
 39.1785 +        if (bestStamp == domStamp ||
 39.1786 +           (bestStamp == womStamp && stamp[WEEK_OF_MONTH] >= stamp[WEEK_OF_YEAR]) ||
 39.1787 +           (bestStamp == dowimStamp && stamp[DAY_OF_WEEK_IN_MONTH] >= stamp[WEEK_OF_YEAR])) {
 39.1788 +            fieldMask |= MONTH_MASK;
 39.1789 +            if (bestStamp == domStamp) {
 39.1790 +                fieldMask |= DAY_OF_MONTH_MASK;
 39.1791 +            } else {
 39.1792 +                assert (bestStamp == womStamp || bestStamp == dowimStamp);
 39.1793 +                if (dowStamp != UNSET) {
 39.1794 +                    fieldMask |= DAY_OF_WEEK_MASK;
 39.1795 +                }
 39.1796 +                if (womStamp == dowimStamp) {
 39.1797 +                    // When they are equal, give the priority to
 39.1798 +                    // WEEK_OF_MONTH for compatibility.
 39.1799 +                    if (stamp[WEEK_OF_MONTH] >= stamp[DAY_OF_WEEK_IN_MONTH]) {
 39.1800 +                        fieldMask |= WEEK_OF_MONTH_MASK;
 39.1801 +                    } else {
 39.1802 +                        fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
 39.1803 +                    }
 39.1804 +                } else {
 39.1805 +                    if (bestStamp == womStamp) {
 39.1806 +                        fieldMask |= WEEK_OF_MONTH_MASK;
 39.1807 +                    } else {
 39.1808 +                        assert (bestStamp == dowimStamp);
 39.1809 +                        if (stamp[DAY_OF_WEEK_IN_MONTH] != UNSET) {
 39.1810 +                            fieldMask |= DAY_OF_WEEK_IN_MONTH_MASK;
 39.1811 +                        }
 39.1812 +                    }
 39.1813 +                }
 39.1814 +            }
 39.1815 +        } else {
 39.1816 +            assert (bestStamp == doyStamp || bestStamp == woyStamp ||
 39.1817 +                    bestStamp == UNSET);
 39.1818 +            if (bestStamp == doyStamp) {
 39.1819 +                fieldMask |= DAY_OF_YEAR_MASK;
 39.1820 +            } else {
 39.1821 +                assert (bestStamp == woyStamp);
 39.1822 +                if (dowStamp != UNSET) {
 39.1823 +                    fieldMask |= DAY_OF_WEEK_MASK;
 39.1824 +                }
 39.1825 +                fieldMask |= WEEK_OF_YEAR_MASK;
 39.1826 +            }
 39.1827 +        }
 39.1828 +
 39.1829 +        // Find the best set of fields specifying the time of day.  There
 39.1830 +        // are only two possibilities here; the HOUR_OF_DAY or the
 39.1831 +        // AM_PM and the HOUR.
 39.1832 +        int hourOfDayStamp = stamp[HOUR_OF_DAY];
 39.1833 +        int hourStamp = aggregateStamp(stamp[HOUR], stamp[AM_PM]);
 39.1834 +        bestStamp = (hourStamp > hourOfDayStamp) ? hourStamp : hourOfDayStamp;
 39.1835 +
 39.1836 +        // if bestStamp is still UNSET, then take HOUR or AM_PM. (See 4846659)
 39.1837 +        if (bestStamp == UNSET) {
 39.1838 +            bestStamp = Math.max(stamp[HOUR], stamp[AM_PM]);
 39.1839 +        }
 39.1840 +
 39.1841 +        // Hours
 39.1842 +        if (bestStamp != UNSET) {
 39.1843 +            if (bestStamp == hourOfDayStamp) {
 39.1844 +                fieldMask |= HOUR_OF_DAY_MASK;
 39.1845 +            } else {
 39.1846 +                fieldMask |= HOUR_MASK;
 39.1847 +                if (stamp[AM_PM] != UNSET) {
 39.1848 +                    fieldMask |= AM_PM_MASK;
 39.1849 +                }
 39.1850 +            }
 39.1851 +        }
 39.1852 +        if (stamp[MINUTE] != UNSET) {
 39.1853 +            fieldMask |= MINUTE_MASK;
 39.1854 +        }
 39.1855 +        if (stamp[SECOND] != UNSET) {
 39.1856 +            fieldMask |= SECOND_MASK;
 39.1857 +        }
 39.1858 +        if (stamp[MILLISECOND] != UNSET) {
 39.1859 +            fieldMask |= MILLISECOND_MASK;
 39.1860 +        }
 39.1861 +        if (stamp[ZONE_OFFSET] >= MINIMUM_USER_STAMP) {
 39.1862 +                fieldMask |= ZONE_OFFSET_MASK;
 39.1863 +        }
 39.1864 +        if (stamp[DST_OFFSET] >= MINIMUM_USER_STAMP) {
 39.1865 +            fieldMask |= DST_OFFSET_MASK;
 39.1866 +        }
 39.1867 +
 39.1868 +        return fieldMask;
 39.1869 +    }
 39.1870 +
 39.1871 +    /**
 39.1872 +     * Returns the pseudo-time-stamp for two fields, given their
 39.1873 +     * individual pseudo-time-stamps.  If either of the fields
 39.1874 +     * is unset, then the aggregate is unset.  Otherwise, the
 39.1875 +     * aggregate is the later of the two stamps.
 39.1876 +     */
 39.1877 +    private static final int aggregateStamp(int stamp_a, int stamp_b) {
 39.1878 +        if (stamp_a == UNSET || stamp_b == UNSET) {
 39.1879 +            return UNSET;
 39.1880 +        }
 39.1881 +        return (stamp_a > stamp_b) ? stamp_a : stamp_b;
 39.1882 +    }
 39.1883 +
 39.1884 +    /**
 39.1885 +     * Compares this <code>Calendar</code> to the specified
 39.1886 +     * <code>Object</code>.  The result is <code>true</code> if and only if
 39.1887 +     * the argument is a <code>Calendar</code> object of the same calendar
 39.1888 +     * system that represents the same time value (millisecond offset from the
 39.1889 +     * <a href="#Epoch">Epoch</a>) under the same
 39.1890 +     * <code>Calendar</code> parameters as this object.
 39.1891 +     *
 39.1892 +     * <p>The <code>Calendar</code> parameters are the values represented
 39.1893 +     * by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
 39.1894 +     * <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
 39.1895 +     * methods. If there is any difference in those parameters
 39.1896 +     * between the two <code>Calendar</code>s, this method returns
 39.1897 +     * <code>false</code>.
 39.1898 +     *
 39.1899 +     * <p>Use the {@link #compareTo(Calendar) compareTo} method to
 39.1900 +     * compare only the time values.
 39.1901 +     *
 39.1902 +     * @param obj the object to compare with.
 39.1903 +     * @return <code>true</code> if this object is equal to <code>obj</code>;
 39.1904 +     * <code>false</code> otherwise.
 39.1905 +     */
 39.1906 +    public boolean equals(Object obj) {
 39.1907 +        if (this == obj)
 39.1908 +            return true;
 39.1909 +        try {
 39.1910 +            Calendar that = (Calendar)obj;
 39.1911 +            return compareTo(getMillisOf(that)) == 0 &&
 39.1912 +                lenient == that.lenient &&
 39.1913 +                firstDayOfWeek == that.firstDayOfWeek &&
 39.1914 +                minimalDaysInFirstWeek == that.minimalDaysInFirstWeek &&
 39.1915 +                zone.equals(that.zone);
 39.1916 +        } catch (Exception e) {
 39.1917 +            // Note: GregorianCalendar.computeTime throws
 39.1918 +            // IllegalArgumentException if the ERA value is invalid
 39.1919 +            // even it's in lenient mode.
 39.1920 +        }
 39.1921 +        return false;
 39.1922 +    }
 39.1923 +
 39.1924 +    /**
 39.1925 +     * Returns a hash code for this calendar.
 39.1926 +     *
 39.1927 +     * @return a hash code value for this object.
 39.1928 +     * @since 1.2
 39.1929 +     */
 39.1930 +    public int hashCode() {
 39.1931 +        // 'otheritems' represents the hash code for the previous versions.
 39.1932 +        int otheritems = (lenient ? 1 : 0)
 39.1933 +            | (firstDayOfWeek << 1)
 39.1934 +            | (minimalDaysInFirstWeek << 4)
 39.1935 +            | (zone.hashCode() << 7);
 39.1936 +        long t = getMillisOf(this);
 39.1937 +        return (int) t ^ (int)(t >> 32) ^ otheritems;
 39.1938 +    }
 39.1939 +
 39.1940 +    /**
 39.1941 +     * Returns whether this <code>Calendar</code> represents a time
 39.1942 +     * before the time represented by the specified
 39.1943 +     * <code>Object</code>. This method is equivalent to:
 39.1944 +     * <pre><blockquote>
 39.1945 +     *         compareTo(when) < 0
 39.1946 +     * </blockquote></pre>
 39.1947 +     * if and only if <code>when</code> is a <code>Calendar</code>
 39.1948 +     * instance. Otherwise, the method returns <code>false</code>.
 39.1949 +     *
 39.1950 +     * @param when the <code>Object</code> to be compared
 39.1951 +     * @return <code>true</code> if the time of this
 39.1952 +     * <code>Calendar</code> is before the time represented by
 39.1953 +     * <code>when</code>; <code>false</code> otherwise.
 39.1954 +     * @see     #compareTo(Calendar)
 39.1955 +     */
 39.1956 +    public boolean before(Object when) {
 39.1957 +        return when instanceof Calendar
 39.1958 +            && compareTo((Calendar)when) < 0;
 39.1959 +    }
 39.1960 +
 39.1961 +    /**
 39.1962 +     * Returns whether this <code>Calendar</code> represents a time
 39.1963 +     * after the time represented by the specified
 39.1964 +     * <code>Object</code>. This method is equivalent to:
 39.1965 +     * <pre><blockquote>
 39.1966 +     *         compareTo(when) > 0
 39.1967 +     * </blockquote></pre>
 39.1968 +     * if and only if <code>when</code> is a <code>Calendar</code>
 39.1969 +     * instance. Otherwise, the method returns <code>false</code>.
 39.1970 +     *
 39.1971 +     * @param when the <code>Object</code> to be compared
 39.1972 +     * @return <code>true</code> if the time of this <code>Calendar</code> is
 39.1973 +     * after the time represented by <code>when</code>; <code>false</code>
 39.1974 +     * otherwise.
 39.1975 +     * @see     #compareTo(Calendar)
 39.1976 +     */
 39.1977 +    public boolean after(Object when) {
 39.1978 +        return when instanceof Calendar
 39.1979 +            && compareTo((Calendar)when) > 0;
 39.1980 +    }
 39.1981 +
 39.1982 +    /**
 39.1983 +     * Compares the time values (millisecond offsets from the <a
 39.1984 +     * href="#Epoch">Epoch</a>) represented by two
 39.1985 +     * <code>Calendar</code> objects.
 39.1986 +     *
 39.1987 +     * @param anotherCalendar the <code>Calendar</code> to be compared.
 39.1988 +     * @return the value <code>0</code> if the time represented by the argument
 39.1989 +     * is equal to the time represented by this <code>Calendar</code>; a value
 39.1990 +     * less than <code>0</code> if the time of this <code>Calendar</code> is
 39.1991 +     * before the time represented by the argument; and a value greater than
 39.1992 +     * <code>0</code> if the time of this <code>Calendar</code> is after the
 39.1993 +     * time represented by the argument.
 39.1994 +     * @exception NullPointerException if the specified <code>Calendar</code> is
 39.1995 +     *            <code>null</code>.
 39.1996 +     * @exception IllegalArgumentException if the time value of the
 39.1997 +     * specified <code>Calendar</code> object can't be obtained due to
 39.1998 +     * any invalid calendar values.
 39.1999 +     * @since   1.5
 39.2000 +     */
 39.2001 +    public int compareTo(Calendar anotherCalendar) {
 39.2002 +        return compareTo(getMillisOf(anotherCalendar));
 39.2003 +    }
 39.2004 +
 39.2005 +    /**
 39.2006 +     * Adds or subtracts the specified amount of time to the given calendar field,
 39.2007 +     * based on the calendar's rules. For example, to subtract 5 days from
 39.2008 +     * the current time of the calendar, you can achieve it by calling:
 39.2009 +     * <p><code>add(Calendar.DAY_OF_MONTH, -5)</code>.
 39.2010 +     *
 39.2011 +     * @param field the calendar field.
 39.2012 +     * @param amount the amount of date or time to be added to the field.
 39.2013 +     * @see #roll(int,int)
 39.2014 +     * @see #set(int,int)
 39.2015 +     */
 39.2016 +    abstract public void add(int field, int amount);
 39.2017 +
 39.2018 +    /**
 39.2019 +     * Adds or subtracts (up/down) a single unit of time on the given time
 39.2020 +     * field without changing larger fields. For example, to roll the current
 39.2021 +     * date up by one day, you can achieve it by calling:
 39.2022 +     * <p>roll(Calendar.DATE, true).
 39.2023 +     * When rolling on the year or Calendar.YEAR field, it will roll the year
 39.2024 +     * value in the range between 1 and the value returned by calling
 39.2025 +     * <code>getMaximum(Calendar.YEAR)</code>.
 39.2026 +     * When rolling on the month or Calendar.MONTH field, other fields like
 39.2027 +     * date might conflict and, need to be changed. For instance,
 39.2028 +     * rolling the month on the date 01/31/96 will result in 02/29/96.
 39.2029 +     * When rolling on the hour-in-day or Calendar.HOUR_OF_DAY field, it will
 39.2030 +     * roll the hour value in the range between 0 and 23, which is zero-based.
 39.2031 +     *
 39.2032 +     * @param field the time field.
 39.2033 +     * @param up indicates if the value of the specified time field is to be
 39.2034 +     * rolled up or rolled down. Use true if rolling up, false otherwise.
 39.2035 +     * @see Calendar#add(int,int)
 39.2036 +     * @see Calendar#set(int,int)
 39.2037 +     */
 39.2038 +    abstract public void roll(int field, boolean up);
 39.2039 +
 39.2040 +    /**
 39.2041 +     * Adds the specified (signed) amount to the specified calendar field
 39.2042 +     * without changing larger fields.  A negative amount means to roll
 39.2043 +     * down.
 39.2044 +     *
 39.2045 +     * <p>NOTE:  This default implementation on <code>Calendar</code> just repeatedly calls the
 39.2046 +     * version of {@link #roll(int,boolean) roll()} that rolls by one unit.  This may not
 39.2047 +     * always do the right thing.  For example, if the <code>DAY_OF_MONTH</code> field is 31,
 39.2048 +     * rolling through February will leave it set to 28.  The <code>GregorianCalendar</code>
 39.2049 +     * version of this function takes care of this problem.  Other subclasses
 39.2050 +     * should also provide overrides of this function that do the right thing.
 39.2051 +     *
 39.2052 +     * @param field the calendar field.
 39.2053 +     * @param amount the signed amount to add to the calendar <code>field</code>.
 39.2054 +     * @since 1.2
 39.2055 +     * @see #roll(int,boolean)
 39.2056 +     * @see #add(int,int)
 39.2057 +     * @see #set(int,int)
 39.2058 +     */
 39.2059 +    public void roll(int field, int amount)
 39.2060 +    {
 39.2061 +        while (amount > 0) {
 39.2062 +            roll(field, true);
 39.2063 +            amount--;
 39.2064 +        }
 39.2065 +        while (amount < 0) {
 39.2066 +            roll(field, false);
 39.2067 +            amount++;
 39.2068 +        }
 39.2069 +    }
 39.2070 +
 39.2071 +    /**
 39.2072 +     * Sets the time zone with the given time zone value.
 39.2073 +     *
 39.2074 +     * @param value the given time zone.
 39.2075 +     */
 39.2076 +    public void setTimeZone(TimeZone value)
 39.2077 +    {
 39.2078 +        zone = value;
 39.2079 +        sharedZone = false;
 39.2080 +        /* Recompute the fields from the time using the new zone.  This also
 39.2081 +         * works if isTimeSet is false (after a call to set()).  In that case
 39.2082 +         * the time will be computed from the fields using the new zone, then
 39.2083 +         * the fields will get recomputed from that.  Consider the sequence of
 39.2084 +         * calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST).
 39.2085 +         * Is cal set to 1 o'clock EST or 1 o'clock PST?  Answer: PST.  More
 39.2086 +         * generally, a call to setTimeZone() affects calls to set() BEFORE AND
 39.2087 +         * AFTER it up to the next call to complete().
 39.2088 +         */
 39.2089 +        areAllFieldsSet = areFieldsSet = false;
 39.2090 +    }
 39.2091 +
 39.2092 +    /**
 39.2093 +     * Gets the time zone.
 39.2094 +     *
 39.2095 +     * @return the time zone object associated with this calendar.
 39.2096 +     */
 39.2097 +    public TimeZone getTimeZone()
 39.2098 +    {
 39.2099 +        // If the TimeZone object is shared by other Calendar instances, then
 39.2100 +        // create a clone.
 39.2101 +        if (sharedZone) {
 39.2102 +            zone = (TimeZone) zone.clone();
 39.2103 +            sharedZone = false;
 39.2104 +        }
 39.2105 +        return zone;
 39.2106 +    }
 39.2107 +
 39.2108 +    /**
 39.2109 +     * Returns the time zone (without cloning).
 39.2110 +     */
 39.2111 +    TimeZone getZone() {
 39.2112 +        return zone;
 39.2113 +    }
 39.2114 +
 39.2115 +    /**
 39.2116 +     * Sets the sharedZone flag to <code>shared</code>.
 39.2117 +     */
 39.2118 +    void setZoneShared(boolean shared) {
 39.2119 +        sharedZone = shared;
 39.2120 +    }
 39.2121 +
 39.2122 +    /**
 39.2123 +     * Specifies whether or not date/time interpretation is to be lenient.  With
 39.2124 +     * lenient interpretation, a date such as "February 942, 1996" will be
 39.2125 +     * treated as being equivalent to the 941st day after February 1, 1996.
 39.2126 +     * With strict (non-lenient) interpretation, such dates will cause an exception to be
 39.2127 +     * thrown. The default is lenient.
 39.2128 +     *
 39.2129 +     * @param lenient <code>true</code> if the lenient mode is to be turned
 39.2130 +     * on; <code>false</code> if it is to be turned off.
 39.2131 +     * @see #isLenient()
 39.2132 +     * @see java.text.DateFormat#setLenient
 39.2133 +     */
 39.2134 +    public void setLenient(boolean lenient)
 39.2135 +    {
 39.2136 +        this.lenient = lenient;
 39.2137 +    }
 39.2138 +
 39.2139 +    /**
 39.2140 +     * Tells whether date/time interpretation is to be lenient.
 39.2141 +     *
 39.2142 +     * @return <code>true</code> if the interpretation mode of this calendar is lenient;
 39.2143 +     * <code>false</code> otherwise.
 39.2144 +     * @see #setLenient(boolean)
 39.2145 +     */
 39.2146 +    public boolean isLenient()
 39.2147 +    {
 39.2148 +        return lenient;
 39.2149 +    }
 39.2150 +
 39.2151 +    /**
 39.2152 +     * Sets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
 39.2153 +     * <code>MONDAY</code> in France.
 39.2154 +     *
 39.2155 +     * @param value the given first day of the week.
 39.2156 +     * @see #getFirstDayOfWeek()
 39.2157 +     * @see #getMinimalDaysInFirstWeek()
 39.2158 +     */
 39.2159 +    public void setFirstDayOfWeek(int value)
 39.2160 +    {
 39.2161 +        if (firstDayOfWeek == value) {
 39.2162 +            return;
 39.2163 +        }
 39.2164 +        firstDayOfWeek = value;
 39.2165 +        invalidateWeekFields();
 39.2166 +    }
 39.2167 +
 39.2168 +    /**
 39.2169 +     * Gets what the first day of the week is; e.g., <code>SUNDAY</code> in the U.S.,
 39.2170 +     * <code>MONDAY</code> in France.
 39.2171 +     *
 39.2172 +     * @return the first day of the week.
 39.2173 +     * @see #setFirstDayOfWeek(int)
 39.2174 +     * @see #getMinimalDaysInFirstWeek()
 39.2175 +     */
 39.2176 +    public int getFirstDayOfWeek()
 39.2177 +    {
 39.2178 +        return firstDayOfWeek;
 39.2179 +    }
 39.2180 +
 39.2181 +    /**
 39.2182 +     * Sets what the minimal days required in the first week of the year are;
 39.2183 +     * For example, if the first week is defined as one that contains the first
 39.2184 +     * day of the first month of a year, call this method with value 1. If it
 39.2185 +     * must be a full week, use value 7.
 39.2186 +     *
 39.2187 +     * @param value the given minimal days required in the first week
 39.2188 +     * of the year.
 39.2189 +     * @see #getMinimalDaysInFirstWeek()
 39.2190 +     */
 39.2191 +    public void setMinimalDaysInFirstWeek(int value)
 39.2192 +    {
 39.2193 +        if (minimalDaysInFirstWeek == value) {
 39.2194 +            return;
 39.2195 +        }
 39.2196 +        minimalDaysInFirstWeek = value;
 39.2197 +        invalidateWeekFields();
 39.2198 +    }
 39.2199 +
 39.2200 +    /**
 39.2201 +     * Gets what the minimal days required in the first week of the year are;
 39.2202 +     * e.g., if the first week is defined as one that contains the first day
 39.2203 +     * of the first month of a year, this method returns 1. If
 39.2204 +     * the minimal days required must be a full week, this method
 39.2205 +     * returns 7.
 39.2206 +     *
 39.2207 +     * @return the minimal days required in the first week of the year.
 39.2208 +     * @see #setMinimalDaysInFirstWeek(int)
 39.2209 +     */
 39.2210 +    public int getMinimalDaysInFirstWeek()
 39.2211 +    {
 39.2212 +        return minimalDaysInFirstWeek;
 39.2213 +    }
 39.2214 +
 39.2215 +    /**
 39.2216 +     * Returns whether this {@code Calendar} supports week dates.
 39.2217 +     *
 39.2218 +     * <p>The default implementation of this method returns {@code false}.
 39.2219 +     *
 39.2220 +     * @return {@code true} if this {@code Calendar} supports week dates;
 39.2221 +     *         {@code false} otherwise.
 39.2222 +     * @see #getWeekYear()
 39.2223 +     * @see #setWeekDate(int,int,int)
 39.2224 +     * @see #getWeeksInWeekYear()
 39.2225 +     * @since 1.7
 39.2226 +     */
 39.2227 +    public boolean isWeekDateSupported() {
 39.2228 +        return false;
 39.2229 +    }
 39.2230 +
 39.2231 +    /**
 39.2232 +     * Returns the week year represented by this {@code Calendar}. The
 39.2233 +     * week year is in sync with the week cycle. The {@linkplain
 39.2234 +     * #getFirstDayOfWeek() first day of the first week} is the first
 39.2235 +     * day of the week year.
 39.2236 +     *
 39.2237 +     * <p>The default implementation of this method throws an
 39.2238 +     * {@link UnsupportedOperationException}.
 39.2239 +     *
 39.2240 +     * @return the week year of this {@code Calendar}
 39.2241 +     * @exception UnsupportedOperationException
 39.2242 +     *            if any week year numbering isn't supported
 39.2243 +     *            in this {@code Calendar}.
 39.2244 +     * @see #isWeekDateSupported()
 39.2245 +     * @see #getFirstDayOfWeek()
 39.2246 +     * @see #getMinimalDaysInFirstWeek()
 39.2247 +     * @since 1.7
 39.2248 +     */
 39.2249 +    public int getWeekYear() {
 39.2250 +        throw new UnsupportedOperationException();
 39.2251 +    }
 39.2252 +
 39.2253 +    /**
 39.2254 +     * Sets the date of this {@code Calendar} with the the given date
 39.2255 +     * specifiers - week year, week of year, and day of week.
 39.2256 +     *
 39.2257 +     * <p>Unlike the {@code set} method, all of the calendar fields
 39.2258 +     * and {@code time} values are calculated upon return.
 39.2259 +     *
 39.2260 +     * <p>If {@code weekOfYear} is out of the valid week-of-year range
 39.2261 +     * in {@code weekYear}, the {@code weekYear} and {@code
 39.2262 +     * weekOfYear} values are adjusted in lenient mode, or an {@code
 39.2263 +     * IllegalArgumentException} is thrown in non-lenient mode.
 39.2264 +     *
 39.2265 +     * <p>The default implementation of this method throws an
 39.2266 +     * {@code UnsupportedOperationException}.
 39.2267 +     *
 39.2268 +     * @param weekYear   the week year
 39.2269 +     * @param weekOfYear the week number based on {@code weekYear}
 39.2270 +     * @param dayOfWeek  the day of week value: one of the constants
 39.2271 +     *                   for the {@link #DAY_OF_WEEK} field: {@link
 39.2272 +     *                   #SUNDAY}, ..., {@link #SATURDAY}.
 39.2273 +     * @exception IllegalArgumentException
 39.2274 +     *            if any of the given date specifiers is invalid
 39.2275 +     *            or any of the calendar fields are inconsistent
 39.2276 +     *            with the given date specifiers in non-lenient mode
 39.2277 +     * @exception UnsupportedOperationException
 39.2278 +     *            if any week year numbering isn't supported in this
 39.2279 +     *            {@code Calendar}.
 39.2280 +     * @see #isWeekDateSupported()
 39.2281 +     * @see #getFirstDayOfWeek()
 39.2282 +     * @see #getMinimalDaysInFirstWeek()
 39.2283 +     * @since 1.7
 39.2284 +     */
 39.2285 +    public void setWeekDate(int weekYear, int weekOfYear, int dayOfWeek) {
 39.2286 +        throw new UnsupportedOperationException();
 39.2287 +    }
 39.2288 +
 39.2289 +    /**
 39.2290 +     * Returns the number of weeks in the week year represented by this
 39.2291 +     * {@code Calendar}.
 39.2292 +     *
 39.2293 +     * <p>The default implementation of this method throws an
 39.2294 +     * {@code UnsupportedOperationException}.
 39.2295 +     *
 39.2296 +     * @return the number of weeks in the week year.
 39.2297 +     * @exception UnsupportedOperationException
 39.2298 +     *            if any week year numbering isn't supported in this
 39.2299 +     *            {@code Calendar}.
 39.2300 +     * @see #WEEK_OF_YEAR
 39.2301 +     * @see #isWeekDateSupported()
 39.2302 +     * @see #getWeekYear()
 39.2303 +     * @see #getActualMaximum(int)
 39.2304 +     * @since 1.7
 39.2305 +     */
 39.2306 +    public int getWeeksInWeekYear() {
 39.2307 +        throw new UnsupportedOperationException();
 39.2308 +    }
 39.2309 +
 39.2310 +    /**
 39.2311 +     * Returns the minimum value for the given calendar field of this
 39.2312 +     * <code>Calendar</code> instance. The minimum value is defined as
 39.2313 +     * the smallest value returned by the {@link #get(int) get} method
 39.2314 +     * for any possible time value.  The minimum value depends on
 39.2315 +     * calendar system specific parameters of the instance.
 39.2316 +     *
 39.2317 +     * @param field the calendar field.
 39.2318 +     * @return the minimum value for the given calendar field.
 39.2319 +     * @see #getMaximum(int)
 39.2320 +     * @see #getGreatestMinimum(int)
 39.2321 +     * @see #getLeastMaximum(int)
 39.2322 +     * @see #getActualMinimum(int)
 39.2323 +     * @see #getActualMaximum(int)
 39.2324 +     */
 39.2325 +    abstract public int getMinimum(int field);
 39.2326 +
 39.2327 +    /**
 39.2328 +     * Returns the maximum value for the given calendar field of this
 39.2329 +     * <code>Calendar</code> instance. The maximum value is defined as
 39.2330 +     * the largest value returned by the {@link #get(int) get} method
 39.2331 +     * for any possible time value. The maximum value depends on
 39.2332 +     * calendar system specific parameters of the instance.
 39.2333 +     *
 39.2334 +     * @param field the calendar field.
 39.2335 +     * @return the maximum value for the given calendar field.
 39.2336 +     * @see #getMinimum(int)
 39.2337 +     * @see #getGreatestMinimum(int)
 39.2338 +     * @see #getLeastMaximum(int)
 39.2339 +     * @see #getActualMinimum(int)
 39.2340 +     * @see #getActualMaximum(int)
 39.2341 +     */
 39.2342 +    abstract public int getMaximum(int field);
 39.2343 +
 39.2344 +    /**
 39.2345 +     * Returns the highest minimum value for the given calendar field
 39.2346 +     * of this <code>Calendar</code> instance. The highest minimum
 39.2347 +     * value is defined as the largest value returned by {@link
 39.2348 +     * #getActualMinimum(int)} for any possible time value. The
 39.2349 +     * greatest minimum value depends on calendar system specific
 39.2350 +     * parameters of the instance.
 39.2351 +     *
 39.2352 +     * @param field the calendar field.
 39.2353 +     * @return the highest minimum value for the given calendar field.
 39.2354 +     * @see #getMinimum(int)
 39.2355 +     * @see #getMaximum(int)
 39.2356 +     * @see #getLeastMaximum(int)
 39.2357 +     * @see #getActualMinimum(int)
 39.2358 +     * @see #getActualMaximum(int)
 39.2359 +     */
 39.2360 +    abstract public int getGreatestMinimum(int field);
 39.2361 +
 39.2362 +    /**
 39.2363 +     * Returns the lowest maximum value for the given calendar field
 39.2364 +     * of this <code>Calendar</code> instance. The lowest maximum
 39.2365 +     * value is defined as the smallest value returned by {@link
 39.2366 +     * #getActualMaximum(int)} for any possible time value. The least
 39.2367 +     * maximum value depends on calendar system specific parameters of
 39.2368 +     * the instance. For example, a <code>Calendar</code> for the
 39.2369 +     * Gregorian calendar system returns 28 for the
 39.2370 +     * <code>DAY_OF_MONTH</code> field, because the 28th is the last
 39.2371 +     * day of the shortest month of this calendar, February in a
 39.2372 +     * common year.
 39.2373 +     *
 39.2374 +     * @param field the calendar field.
 39.2375 +     * @return the lowest maximum value for the given calendar field.
 39.2376 +     * @see #getMinimum(int)
 39.2377 +     * @see #getMaximum(int)
 39.2378 +     * @see #getGreatestMinimum(int)
 39.2379 +     * @see #getActualMinimum(int)
 39.2380 +     * @see #getActualMaximum(int)
 39.2381 +     */
 39.2382 +    abstract public int getLeastMaximum(int field);
 39.2383 +
 39.2384 +    /**
 39.2385 +     * Returns the minimum value that the specified calendar field
 39.2386 +     * could have, given the time value of this <code>Calendar</code>.
 39.2387 +     *
 39.2388 +     * <p>The default implementation of this method uses an iterative
 39.2389 +     * algorithm to determine the actual minimum value for the
 39.2390 +     * calendar field. Subclasses should, if possible, override this
 39.2391 +     * with a more efficient implementation - in many cases, they can
 39.2392 +     * simply return <code>getMinimum()</code>.
 39.2393 +     *
 39.2394 +     * @param field the calendar field
 39.2395 +     * @return the minimum of the given calendar field for the time
 39.2396 +     * value of this <code>Calendar</code>
 39.2397 +     * @see #getMinimum(int)
 39.2398 +     * @see #getMaximum(int)
 39.2399 +     * @see #getGreatestMinimum(int)
 39.2400 +     * @see #getLeastMaximum(int)
 39.2401 +     * @see #getActualMaximum(int)
 39.2402 +     * @since 1.2
 39.2403 +     */
 39.2404 +    public int getActualMinimum(int field) {
 39.2405 +        int fieldValue = getGreatestMinimum(field);
 39.2406 +        int endValue = getMinimum(field);
 39.2407 +
 39.2408 +        // if we know that the minimum value is always the same, just return it
 39.2409 +        if (fieldValue == endValue) {
 39.2410 +            return fieldValue;
 39.2411 +        }
 39.2412 +
 39.2413 +        // clone the calendar so we don't mess with the real one, and set it to
 39.2414 +        // accept anything for the field values
 39.2415 +        Calendar work = (Calendar)this.clone();
 39.2416 +        work.setLenient(true);
 39.2417 +
 39.2418 +        // now try each value from getLeastMaximum() to getMaximum() one by one until
 39.2419 +        // we get a value that normalizes to another value.  The last value that
 39.2420 +        // normalizes to itself is the actual minimum for the current date
 39.2421 +        int result = fieldValue;
 39.2422 +
 39.2423 +        do {
 39.2424 +            work.set(field, fieldValue);
 39.2425 +            if (work.get(field) != fieldValue) {
 39.2426 +                break;
 39.2427 +            } else {
 39.2428 +                result = fieldValue;
 39.2429 +                fieldValue--;
 39.2430 +            }
 39.2431 +        } while (fieldValue >= endValue);
 39.2432 +
 39.2433 +        return result;
 39.2434 +    }
 39.2435 +
 39.2436 +    /**
 39.2437 +     * Returns the maximum value that the specified calendar field
 39.2438 +     * could have, given the time value of this
 39.2439 +     * <code>Calendar</code>. For example, the actual maximum value of
 39.2440 +     * the <code>MONTH</code> field is 12 in some years, and 13 in
 39.2441 +     * other years in the Hebrew calendar system.
 39.2442 +     *
 39.2443 +     * <p>The default implementation of this method uses an iterative
 39.2444 +     * algorithm to determine the actual maximum value for the
 39.2445 +     * calendar field. Subclasses should, if possible, override this
 39.2446 +     * with a more efficient implementation.
 39.2447 +     *
 39.2448 +     * @param field the calendar field
 39.2449 +     * @return the maximum of the given calendar field for the time
 39.2450 +     * value of this <code>Calendar</code>
 39.2451 +     * @see #getMinimum(int)
 39.2452 +     * @see #getMaximum(int)
 39.2453 +     * @see #getGreatestMinimum(int)
 39.2454 +     * @see #getLeastMaximum(int)
 39.2455 +     * @see #getActualMinimum(int)
 39.2456 +     * @since 1.2
 39.2457 +     */
 39.2458 +    public int getActualMaximum(int field) {
 39.2459 +        int fieldValue = getLeastMaximum(field);
 39.2460 +        int endValue = getMaximum(field);
 39.2461 +
 39.2462 +        // if we know that the maximum value is always the same, just return it.
 39.2463 +        if (fieldValue == endValue) {
 39.2464 +            return fieldValue;
 39.2465 +        }
 39.2466 +
 39.2467 +        // clone the calendar so we don't mess with the real one, and set it to
 39.2468 +        // accept anything for the field values.
 39.2469 +        Calendar work = (Calendar)this.clone();
 39.2470 +        work.setLenient(true);
 39.2471 +
 39.2472 +        // if we're counting weeks, set the day of the week to Sunday.  We know the
 39.2473 +        // last week of a month or year will contain the first day of the week.
 39.2474 +        if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH)
 39.2475 +            work.set(DAY_OF_WEEK, firstDayOfWeek);
 39.2476 +
 39.2477 +        // now try each value from getLeastMaximum() to getMaximum() one by one until
 39.2478 +        // we get a value that normalizes to another value.  The last value that
 39.2479 +        // normalizes to itself is the actual maximum for the current date
 39.2480 +        int result = fieldValue;
 39.2481 +
 39.2482 +        do {
 39.2483 +            work.set(field, fieldValue);
 39.2484 +            if (work.get(field) != fieldValue) {
 39.2485 +                break;
 39.2486 +            } else {
 39.2487 +                result = fieldValue;
 39.2488 +                fieldValue++;
 39.2489 +            }
 39.2490 +        } while (fieldValue <= endValue);
 39.2491 +
 39.2492 +        return result;
 39.2493 +    }
 39.2494 +
 39.2495 +    /**
 39.2496 +     * Creates and returns a copy of this object.
 39.2497 +     *
 39.2498 +     * @return a copy of this object.
 39.2499 +     */
 39.2500 +    public Object clone()
 39.2501 +    {
 39.2502 +        try {
 39.2503 +            Calendar other = (Calendar) super.clone();
 39.2504 +
 39.2505 +            other.fields = new int[FIELD_COUNT];
 39.2506 +            other.isSet = new boolean[FIELD_COUNT];
 39.2507 +            other.stamp = new int[FIELD_COUNT];
 39.2508 +            for (int i = 0; i < FIELD_COUNT; i++) {
 39.2509 +                other.fields[i] = fields[i];
 39.2510 +                other.stamp[i] = stamp[i];
 39.2511 +                other.isSet[i] = isSet[i];
 39.2512 +            }
 39.2513 +            other.zone = (TimeZone) zone.clone();
 39.2514 +            return other;
 39.2515 +        }
 39.2516 +        catch (CloneNotSupportedException e) {
 39.2517 +            // this shouldn't happen, since we are Cloneable
 39.2518 +            throw new InternalError();
 39.2519 +        }
 39.2520 +    }
 39.2521 +
 39.2522 +    private static final String[] FIELD_NAME = {
 39.2523 +        "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
 39.2524 +        "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
 39.2525 +        "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
 39.2526 +        "DST_OFFSET"
 39.2527 +    };
 39.2528 +
 39.2529 +    /**
 39.2530 +     * Returns the name of the specified calendar field.
 39.2531 +     *
 39.2532 +     * @param field the calendar field
 39.2533 +     * @return the calendar field name
 39.2534 +     * @exception IndexOutOfBoundsException if <code>field</code> is negative,
 39.2535 +     * equal to or greater then <code>FIELD_COUNT</code>.
 39.2536 +     */
 39.2537 +    static final String getFieldName(int field) {
 39.2538 +        return FIELD_NAME[field];
 39.2539 +    }
 39.2540 +
 39.2541 +    /**
 39.2542 +     * Return a string representation of this calendar. This method
 39.2543 +     * is intended to be used only for debugging purposes, and the
 39.2544 +     * format of the returned string may vary between implementations.
 39.2545 +     * The returned string may be empty but may not be <code>null</code>.
 39.2546 +     *
 39.2547 +     * @return  a string representation of this calendar.
 39.2548 +     */
 39.2549 +    public String toString() {
 39.2550 +        // NOTE: BuddhistCalendar.toString() interprets the string
 39.2551 +        // produced by this method so that the Gregorian year number
 39.2552 +        // is substituted by its B.E. year value. It relies on
 39.2553 +        // "...,YEAR=<year>,..." or "...,YEAR=?,...".
 39.2554 +        StringBuilder buffer = new StringBuilder(800);
 39.2555 +        buffer.append(getClass().getName()).append('[');
 39.2556 +        appendValue(buffer, "time", isTimeSet, time);
 39.2557 +        buffer.append(",areFieldsSet=").append(areFieldsSet);
 39.2558 +        buffer.append(",areAllFieldsSet=").append(areAllFieldsSet);
 39.2559 +        buffer.append(",lenient=").append(lenient);
 39.2560 +        buffer.append(",zone=").append(zone);
 39.2561 +        appendValue(buffer, ",firstDayOfWeek", true, (long) firstDayOfWeek);
 39.2562 +        appendValue(buffer, ",minimalDaysInFirstWeek", true, (long) minimalDaysInFirstWeek);
 39.2563 +        for (int i = 0; i < FIELD_COUNT; ++i) {
 39.2564 +            buffer.append(',');
 39.2565 +            appendValue(buffer, FIELD_NAME[i], isSet(i), (long) fields[i]);
 39.2566 +        }
 39.2567 +        buffer.append(']');
 39.2568 +        return buffer.toString();
 39.2569 +    }
 39.2570 +
 39.2571 +    // =======================privates===============================
 39.2572 +
 39.2573 +    private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) {
 39.2574 +        sb.append(item).append('=');
 39.2575 +        if (valid) {
 39.2576 +            sb.append(value);
 39.2577 +        } else {
 39.2578 +            sb.append('?');
 39.2579 +        }
 39.2580 +    }
 39.2581 +
 39.2582 +    /**
 39.2583 +     * Both firstDayOfWeek and minimalDaysInFirstWeek are locale-dependent.
 39.2584 +     * They are used to figure out the week count for a specific date for
 39.2585 +     * a given locale. These must be set when a Calendar is constructed.
 39.2586 +     * @param desiredLocale the given locale.
 39.2587 +     */
 39.2588 +    private void setWeekCountData(Locale desiredLocale)
 39.2589 +    {
 39.2590 +        /* try to get the Locale data from the cache */
 39.2591 +        int[] data = cachedLocaleData.get(desiredLocale);
 39.2592 +        if (data == null) {  /* cache miss */
 39.2593 +            ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale);
 39.2594 +            data = new int[2];
 39.2595 +            data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek"));
 39.2596 +            data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek"));
 39.2597 +            cachedLocaleData.putIfAbsent(desiredLocale, data);
 39.2598 +        }
 39.2599 +        firstDayOfWeek = data[0];
 39.2600 +        minimalDaysInFirstWeek = data[1];
 39.2601 +    }
 39.2602 +
 39.2603 +    /**
 39.2604 +     * Recomputes the time and updates the status fields isTimeSet
 39.2605 +     * and areFieldsSet.  Callers should check isTimeSet and only
 39.2606 +     * call this method if isTimeSet is false.
 39.2607 +     */
 39.2608 +    private void updateTime() {
 39.2609 +        computeTime();
 39.2610 +        // The areFieldsSet and areAllFieldsSet values are no longer
 39.2611 +        // controlled here (as of 1.5).
 39.2612 +        isTimeSet = true;
 39.2613 +    }
 39.2614 +
 39.2615 +    private int compareTo(long t) {
 39.2616 +        long thisTime = getMillisOf(this);
 39.2617 +        return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1;
 39.2618 +    }
 39.2619 +
 39.2620 +    private static final long getMillisOf(Calendar calendar) {
 39.2621 +        if (calendar.isTimeSet) {
 39.2622 +            return calendar.time;
 39.2623 +        }
 39.2624 +        Calendar cal = (Calendar) calendar.clone();
 39.2625 +        cal.setLenient(true);
 39.2626 +        return cal.getTimeInMillis();
 39.2627 +    }
 39.2628 +
 39.2629 +    /**
 39.2630 +     * Adjusts the stamp[] values before nextStamp overflow. nextStamp
 39.2631 +     * is set to the next stamp value upon the return.
 39.2632 +     */
 39.2633 +    private final void adjustStamp() {
 39.2634 +        int max = MINIMUM_USER_STAMP;
 39.2635 +        int newStamp = MINIMUM_USER_STAMP;
 39.2636 +
 39.2637 +        for (;;) {
 39.2638 +            int min = Integer.MAX_VALUE;
 39.2639 +            for (int i = 0; i < stamp.length; i++) {
 39.2640 +                int v = stamp[i];
 39.2641 +                if (v >= newStamp && min > v) {
 39.2642 +                    min = v;
 39.2643 +                }
 39.2644 +                if (max < v) {
 39.2645 +                    max = v;
 39.2646 +                }
 39.2647 +            }
 39.2648 +            if (max != min && min == Integer.MAX_VALUE) {
 39.2649 +                break;
 39.2650 +            }
 39.2651 +            for (int i = 0; i < stamp.length; i++) {
 39.2652 +                if (stamp[i] == min) {
 39.2653 +                    stamp[i] = newStamp;
 39.2654 +                }
 39.2655 +            }
 39.2656 +            newStamp++;
 39.2657 +            if (min == max) {
 39.2658 +                break;
 39.2659 +            }
 39.2660 +        }
 39.2661 +        nextStamp = newStamp;
 39.2662 +    }
 39.2663 +
 39.2664 +    /**
 39.2665 +     * Sets the WEEK_OF_MONTH and WEEK_OF_YEAR fields to new values with the
 39.2666 +     * new parameter value if they have been calculated internally.
 39.2667 +     */
 39.2668 +    private void invalidateWeekFields()
 39.2669 +    {
 39.2670 +        if (stamp[WEEK_OF_MONTH] != COMPUTED &&
 39.2671 +            stamp[WEEK_OF_YEAR] != COMPUTED) {
 39.2672 +            return;
 39.2673 +        }
 39.2674 +
 39.2675 +        // We have to check the new values of these fields after changing
 39.2676 +        // firstDayOfWeek and/or minimalDaysInFirstWeek. If the field values
 39.2677 +        // have been changed, then set the new values. (4822110)
 39.2678 +        Calendar cal = (Calendar) clone();
 39.2679 +        cal.setLenient(true);
 39.2680 +        cal.clear(WEEK_OF_MONTH);
 39.2681 +        cal.clear(WEEK_OF_YEAR);
 39.2682 +
 39.2683 +        if (stamp[WEEK_OF_MONTH] == COMPUTED) {
 39.2684 +            int weekOfMonth = cal.get(WEEK_OF_MONTH);
 39.2685 +            if (fields[WEEK_OF_MONTH] != weekOfMonth) {
 39.2686 +                fields[WEEK_OF_MONTH] = weekOfMonth;
 39.2687 +            }
 39.2688 +        }
 39.2689 +
 39.2690 +        if (stamp[WEEK_OF_YEAR] == COMPUTED) {
 39.2691 +            int weekOfYear = cal.get(WEEK_OF_YEAR);
 39.2692 +            if (fields[WEEK_OF_YEAR] != weekOfYear) {
 39.2693 +                fields[WEEK_OF_YEAR] = weekOfYear;
 39.2694 +            }
 39.2695 +        }
 39.2696 +    }
 39.2697 +
 39.2698 +    /**
 39.2699 +     * Save the state of this object to a stream (i.e., serialize it).
 39.2700 +     *
 39.2701 +     * Ideally, <code>Calendar</code> would only write out its state data and
 39.2702 +     * the current time, and not write any field data out, such as
 39.2703 +     * <code>fields[]</code>, <code>isTimeSet</code>, <code>areFieldsSet</code>,
 39.2704 +     * and <code>isSet[]</code>.  <code>nextStamp</code> also should not be part
 39.2705 +     * of the persistent state. Unfortunately, this didn't happen before JDK 1.1
 39.2706 +     * shipped. To be compatible with JDK 1.1, we will always have to write out
 39.2707 +     * the field values and state flags.  However, <code>nextStamp</code> can be
 39.2708 +     * removed from the serialization stream; this will probably happen in the
 39.2709 +     * near future.
 39.2710 +     */
 39.2711 +    private void writeObject(ObjectOutputStream stream)
 39.2712 +         throws IOException
 39.2713 +    {
 39.2714 +        // Try to compute the time correctly, for the future (stream
 39.2715 +        // version 2) in which we don't write out fields[] or isSet[].
 39.2716 +        if (!isTimeSet) {
 39.2717 +            try {
 39.2718 +                updateTime();
 39.2719 +            }
 39.2720 +            catch (IllegalArgumentException e) {}
 39.2721 +        }
 39.2722 +
 39.2723 +        // If this Calendar has a ZoneInfo, save it and set a
 39.2724 +        // SimpleTimeZone equivalent (as a single DST schedule) for
 39.2725 +        // backward compatibility.
 39.2726 +        TimeZone savedZone = null;
 39.2727 +        if (zone instanceof ZoneInfo) {
 39.2728 +            SimpleTimeZone stz = ((ZoneInfo)zone).getLastRuleInstance();
 39.2729 +            if (stz == null) {
 39.2730 +                stz = new SimpleTimeZone(zone.getRawOffset(), zone.getID());
 39.2731 +            }
 39.2732 +            savedZone = zone;
 39.2733 +            zone = stz;
 39.2734 +        }
 39.2735 +
 39.2736 +        // Write out the 1.1 FCS object.
 39.2737 +        stream.defaultWriteObject();
 39.2738 +
 39.2739 +        // Write out the ZoneInfo object
 39.2740 +        // 4802409: we write out even if it is null, a temporary workaround
 39.2741 +        // the real fix for bug 4844924 in corba-iiop
 39.2742 +        stream.writeObject(savedZone);
 39.2743 +        if (savedZone != null) {
 39.2744 +            zone = savedZone;
 39.2745 +        }
 39.2746 +    }
 39.2747 +
 39.2748 +    private static class CalendarAccessControlContext {
 39.2749 +        private static final AccessControlContext INSTANCE;
 39.2750 +        static {
 39.2751 +            RuntimePermission perm = new RuntimePermission("accessClassInPackage.sun.util.calendar");
 39.2752 +            PermissionCollection perms = perm.newPermissionCollection();
 39.2753 +            perms.add(perm);
 39.2754 +            INSTANCE = new AccessControlContext(new ProtectionDomain[] {
 39.2755 +                                                    new ProtectionDomain(null, perms)
 39.2756 +                                                });
 39.2757 +        }
 39.2758 +    }
 39.2759 +
 39.2760 +    /**
 39.2761 +     * Reconstitutes this object from a stream (i.e., deserialize it).
 39.2762 +     */
 39.2763 +    private void readObject(ObjectInputStream stream)
 39.2764 +         throws IOException, ClassNotFoundException
 39.2765 +    {
 39.2766 +        final ObjectInputStream input = stream;
 39.2767 +        input.defaultReadObject();
 39.2768 +
 39.2769 +        stamp = new int[FIELD_COUNT];
 39.2770 +
 39.2771 +        // Starting with version 2 (not implemented yet), we expect that
 39.2772 +        // fields[], isSet[], isTimeSet, and areFieldsSet may not be
 39.2773 +        // streamed out anymore.  We expect 'time' to be correct.
 39.2774 +        if (serialVersionOnStream >= 2)
 39.2775 +        {
 39.2776 +            isTimeSet = true;
 39.2777 +            if (fields == null) fields = new int[FIELD_COUNT];
 39.2778 +            if (isSet == null) isSet = new boolean[FIELD_COUNT];
 39.2779 +        }
 39.2780 +        else if (serialVersionOnStream >= 0)
 39.2781 +        {
 39.2782 +            for (int i=0; i<FIELD_COUNT; ++i)
 39.2783 +                stamp[i] = isSet[i] ? COMPUTED : UNSET;
 39.2784 +        }
 39.2785 +
 39.2786 +        serialVersionOnStream = currentSerialVersion;
 39.2787 +
 39.2788 +        // If there's a ZoneInfo object, use it for zone.
 39.2789 +        ZoneInfo zi = null;
 39.2790 +        try {
 39.2791 +            zi = AccessController.doPrivileged(
 39.2792 +                    new PrivilegedExceptionAction<ZoneInfo>() {
 39.2793 +                        public ZoneInfo run() throws Exception {
 39.2794 +                            return (ZoneInfo) input.readObject();
 39.2795 +                        }
 39.2796 +                    },
 39.2797 +                    CalendarAccessControlContext.INSTANCE);
 39.2798 +        } catch (PrivilegedActionException pae) {
 39.2799 +            Exception e = pae.getException();
 39.2800 +            if (!(e instanceof OptionalDataException)) {
 39.2801 +                if (e instanceof RuntimeException) {
 39.2802 +                    throw (RuntimeException) e;
 39.2803 +                } else if (e instanceof IOException) {
 39.2804 +                    throw (IOException) e;
 39.2805 +                } else if (e instanceof ClassNotFoundException) {
 39.2806 +                    throw (ClassNotFoundException) e;
 39.2807 +                }
 39.2808 +                throw new RuntimeException(e);
 39.2809 +            }
 39.2810 +        }
 39.2811 +        if (zi != null) {
 39.2812 +            zone = zi;
 39.2813 +        }
 39.2814 +
 39.2815 +        // If the deserialized object has a SimpleTimeZone, try to
 39.2816 +        // replace it with a ZoneInfo equivalent (as of 1.4) in order
 39.2817 +        // to be compatible with the SimpleTimeZone-based
 39.2818 +        // implementation as much as possible.
 39.2819 +        if (zone instanceof SimpleTimeZone) {
 39.2820 +            String id = zone.getID();
 39.2821 +            TimeZone tz = TimeZone.getTimeZone(id);
 39.2822 +            if (tz != null && tz.hasSameRules(zone) && tz.getID().equals(id)) {
 39.2823 +                zone = tz;
 39.2824 +            }
 39.2825 +        }
 39.2826 +    }
 39.2827 +}
    40.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    40.2 +++ b/rt/emul/compact/src/main/java/java/util/Currency.java	Thu Oct 03 15:40:35 2013 +0200
    40.3 @@ -0,0 +1,741 @@
    40.4 +/*
    40.5 + * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
    40.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    40.7 + *
    40.8 + * This code is free software; you can redistribute it and/or modify it
    40.9 + * under the terms of the GNU General Public License version 2 only, as
   40.10 + * published by the Free Software Foundation.  Oracle designates this
   40.11 + * particular file as subject to the "Classpath" exception as provided
   40.12 + * by Oracle in the LICENSE file that accompanied this code.
   40.13 + *
   40.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   40.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   40.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   40.17 + * version 2 for more details (a copy is included in the LICENSE file that
   40.18 + * accompanied this code).
   40.19 + *
   40.20 + * You should have received a copy of the GNU General Public License version
   40.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   40.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   40.23 + *
   40.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   40.25 + * or visit www.oracle.com if you need additional information or have any
   40.26 + * questions.
   40.27 + */
   40.28 +
   40.29 +package java.util;
   40.30 +
   40.31 +import java.io.BufferedInputStream;
   40.32 +import java.io.DataInputStream;
   40.33 +import java.io.File;
   40.34 +import java.io.FileInputStream;
   40.35 +import java.io.FileReader;
   40.36 +import java.io.IOException;
   40.37 +import java.io.Serializable;
   40.38 +import java.security.AccessController;
   40.39 +import java.security.PrivilegedAction;
   40.40 +import java.util.logging.Level;
   40.41 +import java.util.regex.Pattern;
   40.42 +import java.util.regex.Matcher;
   40.43 +import java.util.spi.CurrencyNameProvider;
   40.44 +import java.util.spi.LocaleServiceProvider;
   40.45 +import sun.util.LocaleServiceProviderPool;
   40.46 +import sun.util.logging.PlatformLogger;
   40.47 +import sun.util.resources.LocaleData;
   40.48 +import sun.util.resources.OpenListResourceBundle;
   40.49 +
   40.50 +
   40.51 +/**
   40.52 + * Represents a currency. Currencies are identified by their ISO 4217 currency
   40.53 + * codes. Visit the <a href="http://www.iso.org/iso/en/prods-services/popstds/currencycodes.html">
   40.54 + * ISO web site</a> for more information, including a table of
   40.55 + * currency codes.
   40.56 + * <p>
   40.57 + * The class is designed so that there's never more than one
   40.58 + * <code>Currency</code> instance for any given currency. Therefore, there's
   40.59 + * no public constructor. You obtain a <code>Currency</code> instance using
   40.60 + * the <code>getInstance</code> methods.
   40.61 + * <p>
   40.62 + * Users can supersede the Java runtime currency data by creating a properties
   40.63 + * file named <code>&lt;JAVA_HOME&gt;/lib/currency.properties</code>.  The contents
   40.64 + * of the properties file are key/value pairs of the ISO 3166 country codes
   40.65 + * and the ISO 4217 currency data respectively.  The value part consists of
   40.66 + * three ISO 4217 values of a currency, i.e., an alphabetic code, a numeric
   40.67 + * code, and a minor unit.  Those three ISO 4217 values are separated by commas.
   40.68 + * The lines which start with '#'s are considered comment lines.  For example,
   40.69 + * <p>
   40.70 + * <code>
   40.71 + * #Sample currency properties<br>
   40.72 + * JP=JPZ,999,0
   40.73 + * </code>
   40.74 + * <p>
   40.75 + * will supersede the currency data for Japan.
   40.76 + *
   40.77 + * @since 1.4
   40.78 + */
   40.79 +public final class Currency implements Serializable {
   40.80 +
   40.81 +    private static final long serialVersionUID = -158308464356906721L;
   40.82 +
   40.83 +    /**
   40.84 +     * ISO 4217 currency code for this currency.
   40.85 +     *
   40.86 +     * @serial
   40.87 +     */
   40.88 +    private final String currencyCode;
   40.89 +
   40.90 +    /**
   40.91 +     * Default fraction digits for this currency.
   40.92 +     * Set from currency data tables.
   40.93 +     */
   40.94 +    transient private final int defaultFractionDigits;
   40.95 +
   40.96 +    /**
   40.97 +     * ISO 4217 numeric code for this currency.
   40.98 +     * Set from currency data tables.
   40.99 +     */
  40.100 +    transient private final int numericCode;
  40.101 +
  40.102 +
  40.103 +    // class data: instance map
  40.104 +
  40.105 +    private static HashMap<String, Currency> instances = new HashMap<String, Currency>(7);
  40.106 +    private static HashSet<Currency> available;
  40.107 +
  40.108 +
  40.109 +    // Class data: currency data obtained from currency.data file.
  40.110 +    // Purpose:
  40.111 +    // - determine valid country codes
  40.112 +    // - determine valid currency codes
  40.113 +    // - map country codes to currency codes
  40.114 +    // - obtain default fraction digits for currency codes
  40.115 +    //
  40.116 +    // sc = special case; dfd = default fraction digits
  40.117 +    // Simple countries are those where the country code is a prefix of the
  40.118 +    // currency code, and there are no known plans to change the currency.
  40.119 +    //
  40.120 +    // table formats:
  40.121 +    // - mainTable:
  40.122 +    //   - maps country code to 32-bit int
  40.123 +    //   - 26*26 entries, corresponding to [A-Z]*[A-Z]
  40.124 +    //   - \u007F -> not valid country
  40.125 +    //   - bits 18-31: unused
  40.126 +    //   - bits 8-17: numeric code (0 to 1023)
  40.127 +    //   - bit 7: 1 - special case, bits 0-4 indicate which one
  40.128 +    //            0 - simple country, bits 0-4 indicate final char of currency code
  40.129 +    //   - bits 5-6: fraction digits for simple countries, 0 for special cases
  40.130 +    //   - bits 0-4: final char for currency code for simple country, or ID of special case
  40.131 +    // - special case IDs:
  40.132 +    //   - 0: country has no currency
  40.133 +    //   - other: index into sc* arrays + 1
  40.134 +    // - scCutOverTimes: cut-over time in millis as returned by
  40.135 +    //   System.currentTimeMillis for special case countries that are changing
  40.136 +    //   currencies; Long.MAX_VALUE for countries that are not changing currencies
  40.137 +    // - scOldCurrencies: old currencies for special case countries
  40.138 +    // - scNewCurrencies: new currencies for special case countries that are
  40.139 +    //   changing currencies; null for others
  40.140 +    // - scOldCurrenciesDFD: default fraction digits for old currencies
  40.141 +    // - scNewCurrenciesDFD: default fraction digits for new currencies, 0 for
  40.142 +    //   countries that are not changing currencies
  40.143 +    // - otherCurrencies: concatenation of all currency codes that are not the
  40.144 +    //   main currency of a simple country, separated by "-"
  40.145 +    // - otherCurrenciesDFD: decimal format digits for currencies in otherCurrencies, same order
  40.146 +
  40.147 +    static int formatVersion;
  40.148 +    static int dataVersion;
  40.149 +    static int[] mainTable;
  40.150 +    static long[] scCutOverTimes;
  40.151 +    static String[] scOldCurrencies;
  40.152 +    static String[] scNewCurrencies;
  40.153 +    static int[] scOldCurrenciesDFD;
  40.154 +    static int[] scNewCurrenciesDFD;
  40.155 +    static int[] scOldCurrenciesNumericCode;
  40.156 +    static int[] scNewCurrenciesNumericCode;
  40.157 +    static String otherCurrencies;
  40.158 +    static int[] otherCurrenciesDFD;
  40.159 +    static int[] otherCurrenciesNumericCode;
  40.160 +
  40.161 +    // handy constants - must match definitions in GenerateCurrencyData
  40.162 +    // magic number
  40.163 +    private static final int MAGIC_NUMBER = 0x43757244;
  40.164 +    // number of characters from A to Z
  40.165 +    private static final int A_TO_Z = ('Z' - 'A') + 1;
  40.166 +    // entry for invalid country codes
  40.167 +    private static final int INVALID_COUNTRY_ENTRY = 0x007F;
  40.168 +    // entry for countries without currency
  40.169 +    private static final int COUNTRY_WITHOUT_CURRENCY_ENTRY = 0x0080;
  40.170 +    // mask for simple case country entries
  40.171 +    private static final int SIMPLE_CASE_COUNTRY_MASK = 0x0000;
  40.172 +    // mask for simple case country entry final character
  40.173 +    private static final int SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK = 0x001F;
  40.174 +    // mask for simple case country entry default currency digits
  40.175 +    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK = 0x0060;
  40.176 +    // shift count for simple case country entry default currency digits
  40.177 +    private static final int SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT = 5;
  40.178 +    // mask for special case country entries
  40.179 +    private static final int SPECIAL_CASE_COUNTRY_MASK = 0x0080;
  40.180 +    // mask for special case country index
  40.181 +    private static final int SPECIAL_CASE_COUNTRY_INDEX_MASK = 0x001F;
  40.182 +    // delta from entry index component in main table to index into special case tables
  40.183 +    private static final int SPECIAL_CASE_COUNTRY_INDEX_DELTA = 1;
  40.184 +    // mask for distinguishing simple and special case countries
  40.185 +    private static final int COUNTRY_TYPE_MASK = SIMPLE_CASE_COUNTRY_MASK | SPECIAL_CASE_COUNTRY_MASK;
  40.186 +    // mask for the numeric code of the currency
  40.187 +    private static final int NUMERIC_CODE_MASK = 0x0003FF00;
  40.188 +    // shift count for the numeric code of the currency
  40.189 +    private static final int NUMERIC_CODE_SHIFT = 8;
  40.190 +
  40.191 +    // Currency data format version
  40.192 +    private static final int VALID_FORMAT_VERSION = 1;
  40.193 +
  40.194 +    static {
  40.195 +        AccessController.doPrivileged(new PrivilegedAction() {
  40.196 +            public Object run() {
  40.197 +                String homeDir = System.getProperty("java.home");
  40.198 +                try {
  40.199 +                    String dataFile = homeDir + File.separator +
  40.200 +                            "lib" + File.separator + "currency.data";
  40.201 +                    DataInputStream dis = new DataInputStream(
  40.202 +                        new BufferedInputStream(
  40.203 +                        new FileInputStream(dataFile)));
  40.204 +                    if (dis.readInt() != MAGIC_NUMBER) {
  40.205 +                        throw new InternalError("Currency data is possibly corrupted");
  40.206 +                    }
  40.207 +                    formatVersion = dis.readInt();
  40.208 +                    if (formatVersion != VALID_FORMAT_VERSION) {
  40.209 +                        throw new InternalError("Currency data format is incorrect");
  40.210 +                    }
  40.211 +                    dataVersion = dis.readInt();
  40.212 +                    mainTable = readIntArray(dis, A_TO_Z * A_TO_Z);
  40.213 +                    int scCount = dis.readInt();
  40.214 +                    scCutOverTimes = readLongArray(dis, scCount);
  40.215 +                    scOldCurrencies = readStringArray(dis, scCount);
  40.216 +                    scNewCurrencies = readStringArray(dis, scCount);
  40.217 +                    scOldCurrenciesDFD = readIntArray(dis, scCount);
  40.218 +                    scNewCurrenciesDFD = readIntArray(dis, scCount);
  40.219 +                    scOldCurrenciesNumericCode = readIntArray(dis, scCount);
  40.220 +                    scNewCurrenciesNumericCode = readIntArray(dis, scCount);
  40.221 +                    int ocCount = dis.readInt();
  40.222 +                    otherCurrencies = dis.readUTF();
  40.223 +                    otherCurrenciesDFD = readIntArray(dis, ocCount);
  40.224 +                    otherCurrenciesNumericCode = readIntArray(dis, ocCount);
  40.225 +                    dis.close();
  40.226 +                } catch (IOException e) {
  40.227 +                    InternalError ie = new InternalError();
  40.228 +                    ie.initCause(e);
  40.229 +                    throw ie;
  40.230 +                }
  40.231 +
  40.232 +                // look for the properties file for overrides
  40.233 +                try {
  40.234 +                    File propFile = new File(homeDir + File.separator +
  40.235 +                                             "lib" + File.separator +
  40.236 +                                             "currency.properties");
  40.237 +                    if (propFile.exists()) {
  40.238 +                        Properties props = new Properties();
  40.239 +                        try (FileReader fr = new FileReader(propFile)) {
  40.240 +                            props.load(fr);
  40.241 +                        }
  40.242 +                        Set<String> keys = props.stringPropertyNames();
  40.243 +                        Pattern propertiesPattern =
  40.244 +                            Pattern.compile("([A-Z]{3})\\s*,\\s*(\\d{3})\\s*,\\s*([0-3])");
  40.245 +                        for (String key : keys) {
  40.246 +                           replaceCurrencyData(propertiesPattern,
  40.247 +                               key.toUpperCase(Locale.ROOT),
  40.248 +                               props.getProperty(key).toUpperCase(Locale.ROOT));
  40.249 +                        }
  40.250 +                    }
  40.251 +                } catch (IOException e) {
  40.252 +                    info("currency.properties is ignored because of an IOException", e);
  40.253 +                }
  40.254 +                return null;
  40.255 +            }
  40.256 +        });
  40.257 +    }
  40.258 +
  40.259 +    /**
  40.260 +     * Constants for retrieving localized names from the name providers.
  40.261 +     */
  40.262 +    private static final int SYMBOL = 0;
  40.263 +    private static final int DISPLAYNAME = 1;
  40.264 +
  40.265 +
  40.266 +    /**
  40.267 +     * Constructs a <code>Currency</code> instance. The constructor is private
  40.268 +     * so that we can insure that there's never more than one instance for a
  40.269 +     * given currency.
  40.270 +     */
  40.271 +    private Currency(String currencyCode, int defaultFractionDigits, int numericCode) {
  40.272 +        this.currencyCode = currencyCode;
  40.273 +        this.defaultFractionDigits = defaultFractionDigits;
  40.274 +        this.numericCode = numericCode;
  40.275 +    }
  40.276 +
  40.277 +    /**
  40.278 +     * Returns the <code>Currency</code> instance for the given currency code.
  40.279 +     *
  40.280 +     * @param currencyCode the ISO 4217 code of the currency
  40.281 +     * @return the <code>Currency</code> instance for the given currency code
  40.282 +     * @exception NullPointerException if <code>currencyCode</code> is null
  40.283 +     * @exception IllegalArgumentException if <code>currencyCode</code> is not
  40.284 +     * a supported ISO 4217 code.
  40.285 +     */
  40.286 +    public static Currency getInstance(String currencyCode) {
  40.287 +        return getInstance(currencyCode, Integer.MIN_VALUE, 0);
  40.288 +    }
  40.289 +
  40.290 +    private static Currency getInstance(String currencyCode, int defaultFractionDigits,
  40.291 +        int numericCode) {
  40.292 +        synchronized (instances) {
  40.293 +            // Try to look up the currency code in the instances table.
  40.294 +            // This does the null pointer check as a side effect.
  40.295 +            // Also, if there already is an entry, the currencyCode must be valid.
  40.296 +            Currency instance = instances.get(currencyCode);
  40.297 +            if (instance != null) {
  40.298 +                return instance;
  40.299 +            }
  40.300 +
  40.301 +            if (defaultFractionDigits == Integer.MIN_VALUE) {
  40.302 +                // Currency code not internally generated, need to verify first
  40.303 +                // A currency code must have 3 characters and exist in the main table
  40.304 +                // or in the list of other currencies.
  40.305 +                if (currencyCode.length() != 3) {
  40.306 +                    throw new IllegalArgumentException();
  40.307 +                }
  40.308 +                char char1 = currencyCode.charAt(0);
  40.309 +                char char2 = currencyCode.charAt(1);
  40.310 +                int tableEntry = getMainTableEntry(char1, char2);
  40.311 +                if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
  40.312 +                        && tableEntry != INVALID_COUNTRY_ENTRY
  40.313 +                        && currencyCode.charAt(2) - 'A' == (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK)) {
  40.314 +                    defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
  40.315 +                    numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
  40.316 +                } else {
  40.317 +                    // Check for '-' separately so we don't get false hits in the table.
  40.318 +                    if (currencyCode.charAt(2) == '-') {
  40.319 +                        throw new IllegalArgumentException();
  40.320 +                    }
  40.321 +                    int index = otherCurrencies.indexOf(currencyCode);
  40.322 +                    if (index == -1) {
  40.323 +                        throw new IllegalArgumentException();
  40.324 +                    }
  40.325 +                    defaultFractionDigits = otherCurrenciesDFD[index / 4];
  40.326 +                    numericCode = otherCurrenciesNumericCode[index / 4];
  40.327 +                }
  40.328 +            }
  40.329 +
  40.330 +            instance = new Currency(currencyCode, defaultFractionDigits, numericCode);
  40.331 +            instances.put(currencyCode, instance);
  40.332 +            return instance;
  40.333 +        }
  40.334 +    }
  40.335 +
  40.336 +    /**
  40.337 +     * Returns the <code>Currency</code> instance for the country of the
  40.338 +     * given locale. The language and variant components of the locale
  40.339 +     * are ignored. The result may vary over time, as countries change their
  40.340 +     * currencies. For example, for the original member countries of the
  40.341 +     * European Monetary Union, the method returns the old national currencies
  40.342 +     * until December 31, 2001, and the Euro from January 1, 2002, local time
  40.343 +     * of the respective countries.
  40.344 +     * <p>
  40.345 +     * The method returns <code>null</code> for territories that don't
  40.346 +     * have a currency, such as Antarctica.
  40.347 +     *
  40.348 +     * @param locale the locale for whose country a <code>Currency</code>
  40.349 +     * instance is needed
  40.350 +     * @return the <code>Currency</code> instance for the country of the given
  40.351 +     * locale, or null
  40.352 +     * @exception NullPointerException if <code>locale</code> or its country
  40.353 +     * code is null
  40.354 +     * @exception IllegalArgumentException if the country of the given locale
  40.355 +     * is not a supported ISO 3166 country code.
  40.356 +     */
  40.357 +    public static Currency getInstance(Locale locale) {
  40.358 +        String country = locale.getCountry();
  40.359 +        if (country == null) {
  40.360 +            throw new NullPointerException();
  40.361 +        }
  40.362 +
  40.363 +        if (country.length() != 2) {
  40.364 +            throw new IllegalArgumentException();
  40.365 +        }
  40.366 +
  40.367 +        char char1 = country.charAt(0);
  40.368 +        char char2 = country.charAt(1);
  40.369 +        int tableEntry = getMainTableEntry(char1, char2);
  40.370 +        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
  40.371 +                    && tableEntry != INVALID_COUNTRY_ENTRY) {
  40.372 +            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
  40.373 +            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
  40.374 +            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
  40.375 +            StringBuffer sb = new StringBuffer(country);
  40.376 +            sb.append(finalChar);
  40.377 +            return getInstance(sb.toString(), defaultFractionDigits, numericCode);
  40.378 +        } else {
  40.379 +            // special cases
  40.380 +            if (tableEntry == INVALID_COUNTRY_ENTRY) {
  40.381 +                throw new IllegalArgumentException();
  40.382 +            }
  40.383 +            if (tableEntry == COUNTRY_WITHOUT_CURRENCY_ENTRY) {
  40.384 +                return null;
  40.385 +            } else {
  40.386 +                int index = (tableEntry & SPECIAL_CASE_COUNTRY_INDEX_MASK) - SPECIAL_CASE_COUNTRY_INDEX_DELTA;
  40.387 +                if (scCutOverTimes[index] == Long.MAX_VALUE || System.currentTimeMillis() < scCutOverTimes[index]) {
  40.388 +                    return getInstance(scOldCurrencies[index], scOldCurrenciesDFD[index],
  40.389 +                        scOldCurrenciesNumericCode[index]);
  40.390 +                } else {
  40.391 +                    return getInstance(scNewCurrencies[index], scNewCurrenciesDFD[index],
  40.392 +                        scNewCurrenciesNumericCode[index]);
  40.393 +                }
  40.394 +            }
  40.395 +        }
  40.396 +    }
  40.397 +
  40.398 +    /**
  40.399 +     * Gets the set of available currencies.  The returned set of currencies
  40.400 +     * contains all of the available currencies, which may include currencies
  40.401 +     * that represent obsolete ISO 4217 codes.  The set can be modified
  40.402 +     * without affecting the available currencies in the runtime.
  40.403 +     *
  40.404 +     * @return the set of available currencies.  If there is no currency
  40.405 +     *    available in the runtime, the returned set is empty.
  40.406 +     * @since 1.7
  40.407 +     */
  40.408 +    public static Set<Currency> getAvailableCurrencies() {
  40.409 +        synchronized(Currency.class) {
  40.410 +            if (available == null) {
  40.411 +                available = new HashSet<Currency>(256);
  40.412 +
  40.413 +                // Add simple currencies first
  40.414 +                for (char c1 = 'A'; c1 <= 'Z'; c1 ++) {
  40.415 +                    for (char c2 = 'A'; c2 <= 'Z'; c2 ++) {
  40.416 +                        int tableEntry = getMainTableEntry(c1, c2);
  40.417 +                        if ((tableEntry & COUNTRY_TYPE_MASK) == SIMPLE_CASE_COUNTRY_MASK
  40.418 +                             && tableEntry != INVALID_COUNTRY_ENTRY) {
  40.419 +                            char finalChar = (char) ((tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) + 'A');
  40.420 +                            int defaultFractionDigits = (tableEntry & SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_MASK) >> SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT;
  40.421 +                            int numericCode = (tableEntry & NUMERIC_CODE_MASK) >> NUMERIC_CODE_SHIFT;
  40.422 +                            StringBuilder sb = new StringBuilder();
  40.423 +                            sb.append(c1);
  40.424 +                            sb.append(c2);
  40.425 +                            sb.append(finalChar);
  40.426 +                            available.add(getInstance(sb.toString(), defaultFractionDigits, numericCode));
  40.427 +                        }
  40.428 +                    }
  40.429 +                }
  40.430 +
  40.431 +                // Now add other currencies
  40.432 +                StringTokenizer st = new StringTokenizer(otherCurrencies, "-");
  40.433 +                while (st.hasMoreElements()) {
  40.434 +                    available.add(getInstance((String)st.nextElement()));
  40.435 +                }
  40.436 +            }
  40.437 +        }
  40.438 +
  40.439 +        return (Set<Currency>) available.clone();
  40.440 +    }
  40.441 +
  40.442 +    /**
  40.443 +     * Gets the ISO 4217 currency code of this currency.
  40.444 +     *
  40.445 +     * @return the ISO 4217 currency code of this currency.
  40.446 +     */
  40.447 +    public String getCurrencyCode() {
  40.448 +        return currencyCode;
  40.449 +    }
  40.450 +
  40.451 +    /**
  40.452 +     * Gets the symbol of this currency for the default locale.
  40.453 +     * For example, for the US Dollar, the symbol is "$" if the default
  40.454 +     * locale is the US, while for other locales it may be "US$". If no
  40.455 +     * symbol can be determined, the ISO 4217 currency code is returned.
  40.456 +     *
  40.457 +     * @return the symbol of this currency for the default locale
  40.458 +     */
  40.459 +    public String getSymbol() {
  40.460 +        return getSymbol(Locale.getDefault(Locale.Category.DISPLAY));
  40.461 +    }
  40.462 +
  40.463 +    /**
  40.464 +     * Gets the symbol of this currency for the specified locale.
  40.465 +     * For example, for the US Dollar, the symbol is "$" if the specified
  40.466 +     * locale is the US, while for other locales it may be "US$". If no
  40.467 +     * symbol can be determined, the ISO 4217 currency code is returned.
  40.468 +     *
  40.469 +     * @param locale the locale for which a display name for this currency is
  40.470 +     * needed
  40.471 +     * @return the symbol of this currency for the specified locale
  40.472 +     * @exception NullPointerException if <code>locale</code> is null
  40.473 +     */
  40.474 +    public String getSymbol(Locale locale) {
  40.475 +        try {
  40.476 +            // Check whether a provider can provide an implementation that's closer
  40.477 +            // to the requested locale than what the Java runtime itself can provide.
  40.478 +            LocaleServiceProviderPool pool =
  40.479 +                LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
  40.480 +
  40.481 +            if (pool.hasProviders()) {
  40.482 +                // Assuming that all the country locales include necessary currency
  40.483 +                // symbols in the Java runtime's resources,  so there is no need to
  40.484 +                // examine whether Java runtime's currency resource bundle is missing
  40.485 +                // names.  Therefore, no resource bundle is provided for calling this
  40.486 +                // method.
  40.487 +                String symbol = pool.getLocalizedObject(
  40.488 +                                    CurrencyNameGetter.INSTANCE,
  40.489 +                                    locale, (OpenListResourceBundle)null,
  40.490 +                                    currencyCode, SYMBOL);
  40.491 +                if (symbol != null) {
  40.492 +                    return symbol;
  40.493 +                }
  40.494 +            }
  40.495 +
  40.496 +            ResourceBundle bundle = LocaleData.getCurrencyNames(locale);
  40.497 +            return bundle.getString(currencyCode);
  40.498 +        } catch (MissingResourceException e) {
  40.499 +            // use currency code as symbol of last resort
  40.500 +            return currencyCode;
  40.501 +        }
  40.502 +    }
  40.503 +
  40.504 +    /**
  40.505 +     * Gets the default number of fraction digits used with this currency.
  40.506 +     * For example, the default number of fraction digits for the Euro is 2,
  40.507 +     * while for the Japanese Yen it's 0.
  40.508 +     * In the case of pseudo-currencies, such as IMF Special Drawing Rights,
  40.509 +     * -1 is returned.
  40.510 +     *
  40.511 +     * @return the default number of fraction digits used with this currency
  40.512 +     */
  40.513 +    public int getDefaultFractionDigits() {
  40.514 +        return defaultFractionDigits;
  40.515 +    }
  40.516 +
  40.517 +    /**
  40.518 +     * Returns the ISO 4217 numeric code of this currency.
  40.519 +     *
  40.520 +     * @return the ISO 4217 numeric code of this currency
  40.521 +     * @since 1.7
  40.522 +     */
  40.523 +    public int getNumericCode() {
  40.524 +        return numericCode;
  40.525 +    }
  40.526 +
  40.527 +    /**
  40.528 +     * Gets the name that is suitable for displaying this currency for
  40.529 +     * the default locale.  If there is no suitable display name found
  40.530 +     * for the default locale, the ISO 4217 currency code is returned.
  40.531 +     *
  40.532 +     * @return the display name of this currency for the default locale
  40.533 +     * @since 1.7
  40.534 +     */
  40.535 +    public String getDisplayName() {
  40.536 +        return getDisplayName(Locale.getDefault(Locale.Category.DISPLAY));
  40.537 +    }
  40.538 +
  40.539 +    /**
  40.540 +     * Gets the name that is suitable for displaying this currency for
  40.541 +     * the specified locale.  If there is no suitable display name found
  40.542 +     * for the specified locale, the ISO 4217 currency code is returned.
  40.543 +     *
  40.544 +     * @param locale the locale for which a display name for this currency is
  40.545 +     * needed
  40.546 +     * @return the display name of this currency for the specified locale
  40.547 +     * @exception NullPointerException if <code>locale</code> is null
  40.548 +     * @since 1.7
  40.549 +     */
  40.550 +    public String getDisplayName(Locale locale) {
  40.551 +        try {
  40.552 +            OpenListResourceBundle bundle = LocaleData.getCurrencyNames(locale);
  40.553 +            String result = null;
  40.554 +            String bundleKey = currencyCode.toLowerCase(Locale.ROOT);
  40.555 +
  40.556 +            // Check whether a provider can provide an implementation that's closer
  40.557 +            // to the requested locale than what the Java runtime itself can provide.
  40.558 +            LocaleServiceProviderPool pool =
  40.559 +                LocaleServiceProviderPool.getPool(CurrencyNameProvider.class);
  40.560 +            if (pool.hasProviders()) {
  40.561 +                result = pool.getLocalizedObject(
  40.562 +                                    CurrencyNameGetter.INSTANCE,
  40.563 +                                    locale, bundleKey, bundle, currencyCode, DISPLAYNAME);
  40.564 +            }
  40.565 +
  40.566 +            if (result == null) {
  40.567 +                result = bundle.getString(bundleKey);
  40.568 +            }
  40.569 +
  40.570 +            if (result != null) {
  40.571 +                return result;
  40.572 +            }
  40.573 +        } catch (MissingResourceException e) {
  40.574 +            // fall through
  40.575 +        }
  40.576 +
  40.577 +        // use currency code as symbol of last resort
  40.578 +        return currencyCode;
  40.579 +    }
  40.580 +
  40.581 +    /**
  40.582 +     * Returns the ISO 4217 currency code of this currency.
  40.583 +     *
  40.584 +     * @return the ISO 4217 currency code of this currency
  40.585 +     */
  40.586 +    public String toString() {
  40.587 +        return currencyCode;
  40.588 +    }
  40.589 +
  40.590 +    /**
  40.591 +     * Resolves instances being deserialized to a single instance per currency.
  40.592 +     */
  40.593 +    private Object readResolve() {
  40.594 +        return getInstance(currencyCode);
  40.595 +    }
  40.596 +
  40.597 +    /**
  40.598 +     * Gets the main table entry for the country whose country code consists
  40.599 +     * of char1 and char2.
  40.600 +     */
  40.601 +    private static int getMainTableEntry(char char1, char char2) {
  40.602 +        if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
  40.603 +            throw new IllegalArgumentException();
  40.604 +        }
  40.605 +        return mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')];
  40.606 +    }
  40.607 +
  40.608 +    /**
  40.609 +     * Sets the main table entry for the country whose country code consists
  40.610 +     * of char1 and char2.
  40.611 +     */
  40.612 +    private static void setMainTableEntry(char char1, char char2, int entry) {
  40.613 +        if (char1 < 'A' || char1 > 'Z' || char2 < 'A' || char2 > 'Z') {
  40.614 +            throw new IllegalArgumentException();
  40.615 +        }
  40.616 +        mainTable[(char1 - 'A') * A_TO_Z + (char2 - 'A')] = entry;
  40.617 +    }
  40.618 +
  40.619 +    /**
  40.620 +     * Obtains a localized currency names from a CurrencyNameProvider
  40.621 +     * implementation.
  40.622 +     */
  40.623 +    private static class CurrencyNameGetter
  40.624 +        implements LocaleServiceProviderPool.LocalizedObjectGetter<CurrencyNameProvider,
  40.625 +                                                                   String> {
  40.626 +        private static final CurrencyNameGetter INSTANCE = new CurrencyNameGetter();
  40.627 +
  40.628 +        public String getObject(CurrencyNameProvider currencyNameProvider,
  40.629 +                                Locale locale,
  40.630 +                                String key,
  40.631 +                                Object... params) {
  40.632 +            assert params.length == 1;
  40.633 +            int type = (Integer)params[0];
  40.634 +
  40.635 +            switch(type) {
  40.636 +            case SYMBOL:
  40.637 +                return currencyNameProvider.getSymbol(key, locale);
  40.638 +            case DISPLAYNAME:
  40.639 +                return currencyNameProvider.getDisplayName(key, locale);
  40.640 +            default:
  40.641 +                assert false; // shouldn't happen
  40.642 +            }
  40.643 +
  40.644 +            return null;
  40.645 +        }
  40.646 +    }
  40.647 +
  40.648 +    private static int[] readIntArray(DataInputStream dis, int count) throws IOException {
  40.649 +        int[] ret = new int[count];
  40.650 +        for (int i = 0; i < count; i++) {
  40.651 +            ret[i] = dis.readInt();
  40.652 +        }
  40.653 +
  40.654 +        return ret;
  40.655 +    }
  40.656 +
  40.657 +    private static long[] readLongArray(DataInputStream dis, int count) throws IOException {
  40.658 +        long[] ret = new long[count];
  40.659 +        for (int i = 0; i < count; i++) {
  40.660 +            ret[i] = dis.readLong();
  40.661 +        }
  40.662 +
  40.663 +        return ret;
  40.664 +    }
  40.665 +
  40.666 +    private static String[] readStringArray(DataInputStream dis, int count) throws IOException {
  40.667 +        String[] ret = new String[count];
  40.668 +        for (int i = 0; i < count; i++) {
  40.669 +            ret[i] = dis.readUTF();
  40.670 +        }
  40.671 +
  40.672 +        return ret;
  40.673 +    }
  40.674 +
  40.675 +    /**
  40.676 +     * Replaces currency data found in the currencydata.properties file
  40.677 +     *
  40.678 +     * @param pattern regex pattern for the properties
  40.679 +     * @param ctry country code
  40.680 +     * @param data currency data.  This is a comma separated string that
  40.681 +     *    consists of "three-letter alphabet code", "three-digit numeric code",
  40.682 +     *    and "one-digit (0,1,2, or 3) default fraction digit".
  40.683 +     *    For example, "JPZ,392,0".
  40.684 +     * @throws
  40.685 +     */
  40.686 +    private static void replaceCurrencyData(Pattern pattern, String ctry, String curdata) {
  40.687 +
  40.688 +        if (ctry.length() != 2) {
  40.689 +            // ignore invalid country code
  40.690 +            String message = new StringBuilder()
  40.691 +                .append("The entry in currency.properties for ")
  40.692 +                .append(ctry).append(" is ignored because of the invalid country code.")
  40.693 +                .toString();
  40.694 +            info(message, null);
  40.695 +            return;
  40.696 +        }
  40.697 +
  40.698 +        Matcher m = pattern.matcher(curdata);
  40.699 +        if (!m.find()) {
  40.700 +            // format is not recognized.  ignore the data
  40.701 +            String message = new StringBuilder()
  40.702 +                .append("The entry in currency.properties for ")
  40.703 +                .append(ctry)
  40.704 +                .append(" is ignored because the value format is not recognized.")
  40.705 +                .toString();
  40.706 +            info(message, null);
  40.707 +            return;
  40.708 +        }
  40.709 +
  40.710 +        String code = m.group(1);
  40.711 +        int numeric = Integer.parseInt(m.group(2));
  40.712 +        int fraction = Integer.parseInt(m.group(3));
  40.713 +        int entry = numeric << NUMERIC_CODE_SHIFT;
  40.714 +
  40.715 +        int index;
  40.716 +        for (index = 0; index < scOldCurrencies.length; index++) {
  40.717 +            if (scOldCurrencies[index].equals(code)) {
  40.718 +                break;
  40.719 +            }
  40.720 +        }
  40.721 +
  40.722 +        if (index == scOldCurrencies.length) {
  40.723 +            // simple case
  40.724 +            entry |= (fraction << SIMPLE_CASE_COUNTRY_DEFAULT_DIGITS_SHIFT) |
  40.725 +                     (code.charAt(2) - 'A');
  40.726 +        } else {
  40.727 +            // special case
  40.728 +            entry |= SPECIAL_CASE_COUNTRY_MASK |
  40.729 +                     (index + SPECIAL_CASE_COUNTRY_INDEX_DELTA);
  40.730 +        }
  40.731 +        setMainTableEntry(ctry.charAt(0), ctry.charAt(1), entry);
  40.732 +    }
  40.733 +
  40.734 +    private static void info(String message, Throwable t) {
  40.735 +        PlatformLogger logger = PlatformLogger.getLogger("java.util.Currency");
  40.736 +        if (logger.isLoggable(PlatformLogger.INFO)) {
  40.737 +            if (t != null) {
  40.738 +                logger.info(message, t);
  40.739 +            } else {
  40.740 +                logger.info(message);
  40.741 +            }
  40.742 +        }
  40.743 +    }
  40.744 +}
    41.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    41.2 +++ b/rt/emul/compact/src/main/java/java/util/CurrencyData.properties	Thu Oct 03 15:40:35 2013 +0200
    41.3 @@ -0,0 +1,586 @@
    41.4 +#
    41.5 +# Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
    41.6 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    41.7 +#
    41.8 +# This code is free software; you can redistribute it and/or modify it
    41.9 +# under the terms of the GNU General Public License version 2 only, as
   41.10 +# published by the Free Software Foundation.  Oracle designates this
   41.11 +# particular file as subject to the "Classpath" exception as provided
   41.12 +# by Oracle in the LICENSE file that accompanied this code.
   41.13 +#
   41.14 +# This code is distributed in the hope that it will be useful, but WITHOUT
   41.15 +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   41.16 +# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   41.17 +# version 2 for more details (a copy is included in the LICENSE file that
   41.18 +# accompanied this code).
   41.19 +#
   41.20 +# You should have received a copy of the GNU General Public License version
   41.21 +# 2 along with this work; if not, write to the Free Software Foundation,
   41.22 +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   41.23 +#
   41.24 +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   41.25 +# or visit www.oracle.com if you need additional information or have any
   41.26 +# questions.
   41.27 +#
   41.28 +
   41.29 +formatVersion=1
   41.30 +
   41.31 +# Version of the currency code information in this class.
   41.32 +# It is a serial number that accompanies with each amendment, such as 
   41.33 +# 'MAxxx.doc'
   41.34 +
   41.35 +dataVersion=140
   41.36 +
   41.37 +# List of all valid ISO 4217 currency codes.
   41.38 +# To ensure compatibility, do not remove codes.
   41.39 +
   41.40 +all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036-\
   41.41 +    AWG533-AYM945-AZM031-AZN944-BAM977-BBD052-BDT050-BEF056-BGL100-BGN975-BHD048-BIF108-\
   41.42 +    BMD060-BND096-BOB068-BOV984-BRL986-BSD044-BTN064-BWP072-BYB112-BYR974-\
   41.43 +    BZD084-CAD124-CDF976-CHF756-CLF990-CLP152-CNY156-COP170-CRC188-CSD891-CUP192-\
   41.44 +    CVE132-CYP196-CZK203-DEM276-DJF262-DKK208-DOP214-DZD012-EEK233-EGP818-\
   41.45 +    ERN232-ESP724-ETB230-EUR978-FIM246-FJD242-FKP238-FRF250-GBP826-GEL981-\
   41.46 +    GHC288-GHS936-GIP292-GMD270-GNF324-GRD300-GTQ320-GWP624-GYD328-HKD344-HNL340-\
   41.47 +    HRK191-HTG332-HUF348-IDR360-IEP372-ILS376-INR356-IQD368-IRR364-ISK352-\
   41.48 +    ITL380-JMD388-JOD400-JPY392-KES404-KGS417-KHR116-KMF174-KPW408-KRW410-\
   41.49 +    KWD414-KYD136-KZT398-LAK418-LBP422-LKR144-LRD430-LSL426-LTL440-LUF442-\
   41.50 +    LVL428-LYD434-MAD504-MDL498-MGA969-MGF450-MKD807-MMK104-MNT496-MOP446-MRO478-\
   41.51 +    MTL470-MUR480-MVR462-MWK454-MXN484-MXV979-MYR458-MZM508-MZN943-NAD516-NGN566-\
   41.52 +    NIO558-NLG528-NOK578-NPR524-NZD554-OMR512-PAB590-PEN604-PGK598-PHP608-\
   41.53 +    PKR586-PLN985-PTE620-PYG600-QAR634-ROL946-RON946-RSD941-RUB643-RUR810-RWF646-SAR682-\
   41.54 +    SBD090-SCR690-SDD736-SDG938-SEK752-SGD702-SHP654-SIT705-SKK703-SLL694-SOS706-\
   41.55 +    SRD968-SRG740-STD678-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TND788-TOP776-\
   41.56 +    TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-\
   41.57 +    UYU858-UZS860-VEB862-VEF937-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\
   41.58 +    XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\
   41.59 +    XPT962-XTS963-XXX999-YER886-YUM891-ZAR710-ZMK894-ZWD716-ZWN942
   41.60 +
   41.61 +
   41.62 +# Mappings from ISO 3166 country codes to ISO 4217 currency codes.
   41.63 +#
   41.64 +# Three forms are used:
   41.65 +# Form 1: <country code>=<currency code>
   41.66 +# Form 2: <country code>=<currency code 1>;<time stamp>;<currency code 2>
   41.67 +# Form 3: <country code>=
   41.68 +# Form 1 is used if no future change in currency is known.
   41.69 +# Form 2 indicates that before the specified time currency 1 is used, from
   41.70 +# the specified time currency 2. The time is given in SimpleDateFormat's
   41.71 +# yyyy-MM-dd-HH-mm-ss format in the GMT time zone.
   41.72 +# Form 3 indicates the country doesn't have a currency (the entry is still
   41.73 +# needed to verify that the country code is valid).
   41.74 +#
   41.75 +# The table is based on the following web sites:
   41.76 +# http://www.din.de/gremien/nas/nabd/iso3166ma/codlstp1/db_en.html
   41.77 +# http://www.bsi-global.com/iso4217currency
   41.78 +# http://www.cia.gov/cia/publications/factbook/indexgeo.html
   41.79 +
   41.80 +# AFGHANISTAN
   41.81 +AF=AFN
   41.82 +# \u00c5LAND ISLANDS
   41.83 +AX=EUR
   41.84 +# ALBANIA
   41.85 +AL=ALL
   41.86 +# ALGERIA
   41.87 +DZ=DZD
   41.88 +# AMERICAN SAMOA
   41.89 +AS=USD
   41.90 +# ANDORRA
   41.91 +AD=EUR
   41.92 +# ANGOLA
   41.93 +AO=AOA
   41.94 +# ANGUILLA
   41.95 +AI=XCD
   41.96 +# ANTARCTICA
   41.97 +AQ=
   41.98 +# ANTIGUA AND BARBUDA
   41.99 +AG=XCD
  41.100 +# ARGENTINA
  41.101 +AR=ARS
  41.102 +# ARMENIA
  41.103 +AM=AMD
  41.104 +# ARUBA
  41.105 +AW=AWG
  41.106 +# AUSTRALIA
  41.107 +AU=AUD
  41.108 +# AUSTRIA
  41.109 +AT=EUR
  41.110 +# AZERBAIJAN
  41.111 +AZ=AZM;2005-12-31-20-00-00;AZN
  41.112 +# BAHAMAS
  41.113 +BS=BSD
  41.114 +# BAHRAIN
  41.115 +BH=BHD
  41.116 +# BANGLADESH
  41.117 +BD=BDT
  41.118 +# BARBADOS
  41.119 +BB=BBD
  41.120 +# BELARUS
  41.121 +BY=BYR
  41.122 +# BELGIUM
  41.123 +BE=EUR
  41.124 +# BELIZE
  41.125 +BZ=BZD
  41.126 +# BENIN
  41.127 +BJ=XOF
  41.128 +# BERMUDA
  41.129 +BM=BMD
  41.130 +# BHUTAN
  41.131 +BT=BTN
  41.132 +# BOLIVIA
  41.133 +BO=BOB
  41.134 +# BOSNIA AND HERZEGOVINA
  41.135 +BA=BAM
  41.136 +# BOTSWANA
  41.137 +BW=BWP
  41.138 +# BOUVET ISLAND
  41.139 +BV=NOK
  41.140 +# BRAZIL
  41.141 +BR=BRL
  41.142 +# BRITISH INDIAN OCEAN TERRITORY
  41.143 +IO=USD
  41.144 +# BRUNEI DARUSSALAM
  41.145 +BN=BND
  41.146 +# BULGARIA
  41.147 +BG=BGN
  41.148 +# BURKINA FASO
  41.149 +BF=XOF
  41.150 +# BURUNDI
  41.151 +BI=BIF
  41.152 +# CAMBODIA
  41.153 +KH=KHR
  41.154 +# CAMEROON
  41.155 +CM=XAF
  41.156 +# CANADA
  41.157 +CA=CAD
  41.158 +# CAPE VERDE
  41.159 +CV=CVE
  41.160 +# CAYMAN ISLANDS
  41.161 +KY=KYD
  41.162 +# CENTRAL AFRICAN REPUBLIC
  41.163 +CF=XAF
  41.164 +# CHAD
  41.165 +TD=XAF
  41.166 +# CHILE
  41.167 +CL=CLP
  41.168 +# CHINA
  41.169 +CN=CNY
  41.170 +# CHRISTMAS ISLAND
  41.171 +CX=AUD
  41.172 +# COCOS (KEELING) ISLANDS
  41.173 +CC=AUD
  41.174 +# COLOMBIA
  41.175 +CO=COP
  41.176 +# COMOROS
  41.177 +KM=KMF
  41.178 +# CONGO
  41.179 +CG=XAF
  41.180 +# CONGO, THE DEMOCRATIC REPUBLIC OF THE
  41.181 +CD=CDF
  41.182 +# COOK ISLANDS
  41.183 +CK=NZD
  41.184 +# COSTA RICA
  41.185 +CR=CRC
  41.186 +# COTE D'IVOIRE
  41.187 +CI=XOF
  41.188 +# CROATIA
  41.189 +HR=HRK
  41.190 +# CUBA
  41.191 +CU=CUP
  41.192 +# CYPRUS
  41.193 +CY=EUR
  41.194 +# CZECH REPUBLIC
  41.195 +CZ=CZK
  41.196 +# DENMARK
  41.197 +DK=DKK
  41.198 +# DJIBOUTI
  41.199 +DJ=DJF
  41.200 +# DOMINICA
  41.201 +DM=XCD
  41.202 +# DOMINICAN REPUBLIC
  41.203 +DO=DOP
  41.204 +# ECUADOR
  41.205 +EC=USD
  41.206 +# EGYPT
  41.207 +EG=EGP
  41.208 +# EL SALVADOR
  41.209 +# USD is also legal currency as of 2001/01/01
  41.210 +SV=SVC
  41.211 +# EQUATORIAL GUINEA
  41.212 +GQ=XAF
  41.213 +# ERITREA
  41.214 +ER=ERN
  41.215 +# ESTONIA
  41.216 +EE=EEK
  41.217 +# ETHIOPIA
  41.218 +ET=ETB
  41.219 +# FALKLAND ISLANDS (MALVINAS)
  41.220 +FK=FKP
  41.221 +# FAROE ISLANDS
  41.222 +FO=DKK
  41.223 +# FIJI
  41.224 +FJ=FJD
  41.225 +# FINLAND
  41.226 +FI=EUR
  41.227 +# FRANCE
  41.228 +FR=EUR
  41.229 +# FRENCH GUIANA
  41.230 +GF=EUR
  41.231 +# FRENCH POLYNESIA
  41.232 +PF=XPF
  41.233 +# FRENCH SOUTHERN TERRITORIES
  41.234 +TF=EUR
  41.235 +# GABON
  41.236 +GA=XAF
  41.237 +# GAMBIA
  41.238 +GM=GMD
  41.239 +# GEORGIA
  41.240 +GE=GEL
  41.241 +# GERMANY
  41.242 +DE=EUR
  41.243 +# GHANA
  41.244 +GH=GHS
  41.245 +# GIBRALTAR
  41.246 +GI=GIP
  41.247 +# GREECE
  41.248 +GR=EUR
  41.249 +# GREENLAND
  41.250 +GL=DKK
  41.251 +# GRENADA
  41.252 +GD=XCD
  41.253 +# GUADELOUPE
  41.254 +GP=EUR
  41.255 +# GUAM
  41.256 +GU=USD
  41.257 +# GUATEMALA
  41.258 +GT=GTQ
  41.259 +# GUERNSEY
  41.260 +GG=GBP
  41.261 +# GUINEA
  41.262 +GN=GNF
  41.263 +# GUINEA-BISSAU
  41.264 +GW=XOF
  41.265 +# GUYANA
  41.266 +GY=GYD
  41.267 +# HAITI
  41.268 +HT=HTG
  41.269 +# HEARD ISLAND AND MCDONALD ISLANDS
  41.270 +HM=AUD
  41.271 +# HOLY SEE (VATICAN CITY STATE)
  41.272 +VA=EUR
  41.273 +# HONDURAS
  41.274 +HN=HNL
  41.275 +# HONG KONG
  41.276 +HK=HKD
  41.277 +# HUNGARY
  41.278 +HU=HUF
  41.279 +# ICELAND
  41.280 +IS=ISK
  41.281 +# INDIA
  41.282 +IN=INR
  41.283 +# INDONESIA
  41.284 +ID=IDR
  41.285 +# IRAN, ISLAMIC REPUBLIC OF
  41.286 +IR=IRR
  41.287 +# IRAQ
  41.288 +IQ=IQD
  41.289 +# IRELAND
  41.290 +IE=EUR
  41.291 +# ISLE OF MAN
  41.292 +IM=GBP
  41.293 +# ISRAEL
  41.294 +IL=ILS
  41.295 +# ITALY
  41.296 +IT=EUR
  41.297 +# JAMAICA
  41.298 +JM=JMD
  41.299 +# JAPAN
  41.300 +JP=JPY
  41.301 +# JERSEY
  41.302 +JE=GBP
  41.303 +# JORDAN
  41.304 +JO=JOD
  41.305 +# KAZAKSTAN
  41.306 +KZ=KZT
  41.307 +# KENYA
  41.308 +KE=KES
  41.309 +# KIRIBATI
  41.310 +KI=AUD
  41.311 +# KOREA, DEMOCRATIC PEOPLE'S REPUBLIC OF
  41.312 +KP=KPW
  41.313 +# KOREA, REPUBLIC OF
  41.314 +KR=KRW
  41.315 +# KUWAIT
  41.316 +KW=KWD
  41.317 +# KYRGYZSTAN
  41.318 +KG=KGS
  41.319 +# LAO PEOPLE'S DEMOCRATIC REPUBLIC
  41.320 +LA=LAK
  41.321 +# LATVIA
  41.322 +LV=LVL
  41.323 +# LEBANON
  41.324 +LB=LBP
  41.325 +# LESOTHO
  41.326 +LS=LSL
  41.327 +# LIBERIA
  41.328 +LR=LRD
  41.329 +# LIBYAN ARAB JAMAHIRIYA
  41.330 +LY=LYD
  41.331 +# LIECHTENSTEIN
  41.332 +LI=CHF
  41.333 +# LITHUANIA
  41.334 +LT=LTL
  41.335 +# LUXEMBOURG
  41.336 +LU=EUR
  41.337 +# MACAU
  41.338 +MO=MOP
  41.339 +# MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF
  41.340 +MK=MKD
  41.341 +# MADAGASCAR
  41.342 +MG=MGA
  41.343 +# MALAWI
  41.344 +MW=MWK
  41.345 +# MALAYSIA
  41.346 +MY=MYR
  41.347 +# MALDIVES
  41.348 +MV=MVR
  41.349 +# MALI
  41.350 +ML=XOF
  41.351 +# MALTA
  41.352 +MT=EUR
  41.353 +# MARSHALL ISLANDS
  41.354 +MH=USD
  41.355 +# MARTINIQUE
  41.356 +MQ=EUR
  41.357 +# MAURITANIA
  41.358 +MR=MRO
  41.359 +# MAURITIUS
  41.360 +MU=MUR
  41.361 +# MAYOTTE
  41.362 +YT=EUR
  41.363 +# MEXICO
  41.364 +MX=MXN
  41.365 +# MICRONESIA, FEDERATED STATES OF
  41.366 +FM=USD
  41.367 +# MOLDOVA, REPUBLIC OF
  41.368 +MD=MDL
  41.369 +# MONACO
  41.370 +MC=EUR
  41.371 +# MONGOLIA
  41.372 +MN=MNT
  41.373 +# MONTENEGRO
  41.374 +ME=EUR
  41.375 +# MONTSERRAT
  41.376 +MS=XCD
  41.377 +# MOROCCO
  41.378 +MA=MAD
  41.379 +# MOZAMBIQUE
  41.380 +MZ=MZM;2006-06-30-22-00-00;MZN
  41.381 +# MYANMAR
  41.382 +MM=MMK
  41.383 +# NAMIBIA
  41.384 +NA=NAD
  41.385 +# NAURU
  41.386 +NR=AUD
  41.387 +# NEPAL
  41.388 +NP=NPR
  41.389 +# NETHERLANDS
  41.390 +NL=EUR
  41.391 +# NETHERLANDS ANTILLES
  41.392 +AN=ANG
  41.393 +# NEW CALEDONIA
  41.394 +NC=XPF
  41.395 +# NEW ZEALAND
  41.396 +NZ=NZD
  41.397 +# NICARAGUA
  41.398 +NI=NIO
  41.399 +# NIGER
  41.400 +NE=XOF
  41.401 +# NIGERIA
  41.402 +NG=NGN
  41.403 +# NIUE
  41.404 +NU=NZD
  41.405 +# NORFOLK ISLAND
  41.406 +NF=AUD
  41.407 +# NORTHERN MARIANA ISLANDS
  41.408 +MP=USD
  41.409 +# NORWAY
  41.410 +NO=NOK
  41.411 +# OMAN
  41.412 +OM=OMR
  41.413 +# PAKISTAN
  41.414 +PK=PKR
  41.415 +# PALAU
  41.416 +PW=USD
  41.417 +# PALESTINIAN TERRITORY, OCCUPIED
  41.418 +PS=ILS
  41.419 +# PANAMA
  41.420 +PA=PAB
  41.421 +# PAPUA NEW GUINEA
  41.422 +PG=PGK
  41.423 +# PARAGUAY
  41.424 +PY=PYG
  41.425 +# PERU
  41.426 +PE=PEN
  41.427 +# PHILIPPINES
  41.428 +PH=PHP
  41.429 +# PITCAIRN
  41.430 +PN=NZD
  41.431 +# POLAND
  41.432 +PL=PLN
  41.433 +# PORTUGAL
  41.434 +PT=EUR
  41.435 +# PUERTO RICO
  41.436 +PR=USD
  41.437 +# QATAR
  41.438 +QA=QAR
  41.439 +# REUNION
  41.440 +RE=EUR
  41.441 +# ROMANIA
  41.442 +RO=ROL;2005-06-30-21-00-00;RON
  41.443 +# RUSSIAN FEDERATION
  41.444 +RU=RUB
  41.445 +# RWANDA
  41.446 +RW=RWF
  41.447 +# SAINT BARTHELEMY
  41.448 +BL=EUR
  41.449 +# SAINT HELENA
  41.450 +SH=SHP
  41.451 +# SAINT KITTS AND NEVIS
  41.452 +KN=XCD
  41.453 +# SAINT LUCIA
  41.454 +LC=XCD
  41.455 +# SAINT MARTIN
  41.456 +MF=EUR
  41.457 +# SAINT PIERRE AND MIQUELON
  41.458 +PM=EUR
  41.459 +# SAINT VINCENT AND THE GRENADINES
  41.460 +VC=XCD
  41.461 +# SAMOA
  41.462 +WS=WST
  41.463 +# SAN MARINO
  41.464 +SM=EUR
  41.465 +# SAO TOME AND PRINCIPE
  41.466 +ST=STD
  41.467 +# SAUDI ARABIA
  41.468 +SA=SAR
  41.469 +# SENEGAL
  41.470 +SN=XOF
  41.471 +# SERBIA
  41.472 +RS=RSD
  41.473 +# SERBIA AND MONTENEGRO
  41.474 +CS=CSD
  41.475 +# SEYCHELLES
  41.476 +SC=SCR
  41.477 +# SIERRA LEONE
  41.478 +SL=SLL
  41.479 +# SINGAPORE
  41.480 +SG=SGD
  41.481 +# SLOVAKIA
  41.482 +SK=SKK
  41.483 +# SLOVENIA
  41.484 +SI=EUR
  41.485 +# SOLOMON ISLANDS
  41.486 +SB=SBD
  41.487 +# SOMALIA
  41.488 +SO=SOS
  41.489 +# SOUTH AFRICA
  41.490 +ZA=ZAR
  41.491 +# SOUTH GEORGIA AND THE SOUTH SANDWICH ISLANDS
  41.492 +GS=GBP
  41.493 +# SPAIN
  41.494 +ES=EUR
  41.495 +# SRI LANKA
  41.496 +LK=LKR
  41.497 +# SUDAN
  41.498 +SD=SDG
  41.499 +# SURINAME
  41.500 +SR=SRD
  41.501 +# SVALBARD AND JAN MAYEN
  41.502 +SJ=NOK
  41.503 +# SWAZILAND
  41.504 +SZ=SZL
  41.505 +# SWEDEN
  41.506 +SE=SEK
  41.507 +# SWITZERLAND
  41.508 +CH=CHF
  41.509 +# SYRIAN ARAB REPUBLIC
  41.510 +SY=SYP
  41.511 +# TAIWAN
  41.512 +TW=TWD
  41.513 +# TAJIKISTAN
  41.514 +TJ=TJS
  41.515 +# TANZANIA, UNITED REPUBLIC OF
  41.516 +TZ=TZS
  41.517 +# THAILAND
  41.518 +TH=THB
  41.519 +# TIMOR-LESTE
  41.520 +TL=USD
  41.521 +# TOGO
  41.522 +TG=XOF
  41.523 +# TOKELAU
  41.524 +TK=NZD
  41.525 +# TONGA
  41.526 +TO=TOP
  41.527 +# TRINIDAD AND TOBAGO
  41.528 +TT=TTD
  41.529 +# TUNISIA
  41.530 +TN=TND
  41.531 +# TURKEY
  41.532 +TR=TRL;2004-12-31-22-00-00;TRY
  41.533 +# TURKMENISTAN
  41.534 +TM=TMM
  41.535 +# TURKS AND CAICOS ISLANDS
  41.536 +TC=USD
  41.537 +# TUVALU
  41.538 +TV=AUD
  41.539 +# UGANDA
  41.540 +UG=UGX
  41.541 +# UKRAINE
  41.542 +UA=UAH
  41.543 +# UNITED ARAB EMIRATES
  41.544 +AE=AED
  41.545 +# UNITED KINGDOM
  41.546 +GB=GBP
  41.547 +# UNITED STATES
  41.548 +US=USD
  41.549 +# UNITED STATES MINOR OUTLYING ISLANDS
  41.550 +UM=USD
  41.551 +# URUGUAY
  41.552 +UY=UYU
  41.553 +# UZBEKISTAN
  41.554 +UZ=UZS
  41.555 +# VANUATU
  41.556 +VU=VUV
  41.557 +# VENEZUELA
  41.558 +VE=VEB;2008-01-01-04-00-00;VEF
  41.559 +# VIET NAM
  41.560 +VN=VND
  41.561 +# VIRGIN ISLANDS, BRITISH
  41.562 +VG=USD
  41.563 +# VIRGIN ISLANDS, U.S.
  41.564 +VI=USD
  41.565 +# WALLIS AND FUTUNA
  41.566 +WF=XPF
  41.567 +# WESTERN SAHARA
  41.568 +EH=MAD
  41.569 +# YEMEN
  41.570 +YE=YER
  41.571 +# ZAMBIA
  41.572 +ZM=ZMK
  41.573 +# ZIMBABWE
  41.574 +ZW=ZWD
  41.575 +
  41.576 +
  41.577 +# List of currencies with 0, 1, OR 3 decimals for minor units, or where there
  41.578 +# are no minor units defined. All others use 2 decimals.
  41.579 +
  41.580 +minor0=\
  41.581 +    ADP-BEF-BIF-BYB-BYR-CLF-CLP-DJF-ESP-GNF-\
  41.582 +    GRD-ISK-ITL-JPY-KMF-KRW-LUF-MGF-PYG-PTE-RWF-\
  41.583 +    TPE-TRL-VUV-XAF-XOF-XPF
  41.584 +minor1=
  41.585 +minor3=\
  41.586 +    BHD-IQD-JOD-KWD-LYD-OMR-TND
  41.587 +minorUndefined=\
  41.588 +    XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-\
  41.589 +    XPT-XTS-XXX
    42.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    42.2 +++ b/rt/emul/compact/src/main/java/java/util/Date.java	Thu Oct 03 15:40:35 2013 +0200
    42.3 @@ -0,0 +1,1331 @@
    42.4 +/*
    42.5 + * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
    42.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    42.7 + *
    42.8 + * This code is free software; you can redistribute it and/or modify it
    42.9 + * under the terms of the GNU General Public License version 2 only, as
   42.10 + * published by the Free Software Foundation.  Oracle designates this
   42.11 + * particular file as subject to the "Classpath" exception as provided
   42.12 + * by Oracle in the LICENSE file that accompanied this code.
   42.13 + *
   42.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   42.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   42.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   42.17 + * version 2 for more details (a copy is included in the LICENSE file that
   42.18 + * accompanied this code).
   42.19 + *
   42.20 + * You should have received a copy of the GNU General Public License version
   42.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   42.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   42.23 + *
   42.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   42.25 + * or visit www.oracle.com if you need additional information or have any
   42.26 + * questions.
   42.27 + */
   42.28 +
   42.29 +package java.util;
   42.30 +
   42.31 +import java.text.DateFormat;
   42.32 +import java.io.IOException;
   42.33 +import java.io.ObjectOutputStream;
   42.34 +import java.io.ObjectInputStream;
   42.35 +import java.lang.ref.SoftReference;
   42.36 +import sun.util.calendar.BaseCalendar;
   42.37 +import sun.util.calendar.CalendarDate;
   42.38 +import sun.util.calendar.CalendarSystem;
   42.39 +import sun.util.calendar.CalendarUtils;
   42.40 +import sun.util.calendar.Era;
   42.41 +import sun.util.calendar.Gregorian;
   42.42 +import sun.util.calendar.ZoneInfo;
   42.43 +
   42.44 +/**
   42.45 + * The class <code>Date</code> represents a specific instant
   42.46 + * in time, with millisecond precision.
   42.47 + * <p>
   42.48 + * Prior to JDK&nbsp;1.1, the class <code>Date</code> had two additional
   42.49 + * functions.  It allowed the interpretation of dates as year, month, day, hour,
   42.50 + * minute, and second values.  It also allowed the formatting and parsing
   42.51 + * of date strings.  Unfortunately, the API for these functions was not
   42.52 + * amenable to internationalization.  As of JDK&nbsp;1.1, the
   42.53 + * <code>Calendar</code> class should be used to convert between dates and time
   42.54 + * fields and the <code>DateFormat</code> class should be used to format and
   42.55 + * parse date strings.
   42.56 + * The corresponding methods in <code>Date</code> are deprecated.
   42.57 + * <p>
   42.58 + * Although the <code>Date</code> class is intended to reflect
   42.59 + * coordinated universal time (UTC), it may not do so exactly,
   42.60 + * depending on the host environment of the Java Virtual Machine.
   42.61 + * Nearly all modern operating systems assume that 1&nbsp;day&nbsp;=
   42.62 + * 24&nbsp;&times;&nbsp;60&nbsp;&times;&nbsp;60&nbsp;= 86400 seconds
   42.63 + * in all cases. In UTC, however, about once every year or two there
   42.64 + * is an extra second, called a "leap second." The leap
   42.65 + * second is always added as the last second of the day, and always
   42.66 + * on December 31 or June 30. For example, the last minute of the
   42.67 + * year 1995 was 61 seconds long, thanks to an added leap second.
   42.68 + * Most computer clocks are not accurate enough to be able to reflect
   42.69 + * the leap-second distinction.
   42.70 + * <p>
   42.71 + * Some computer standards are defined in terms of Greenwich mean
   42.72 + * time (GMT), which is equivalent to universal time (UT).  GMT is
   42.73 + * the "civil" name for the standard; UT is the
   42.74 + * "scientific" name for the same standard. The
   42.75 + * distinction between UTC and UT is that UTC is based on an atomic
   42.76 + * clock and UT is based on astronomical observations, which for all
   42.77 + * practical purposes is an invisibly fine hair to split. Because the
   42.78 + * earth's rotation is not uniform (it slows down and speeds up
   42.79 + * in complicated ways), UT does not always flow uniformly. Leap
   42.80 + * seconds are introduced as needed into UTC so as to keep UTC within
   42.81 + * 0.9 seconds of UT1, which is a version of UT with certain
   42.82 + * corrections applied. There are other time and date systems as
   42.83 + * well; for example, the time scale used by the satellite-based
   42.84 + * global positioning system (GPS) is synchronized to UTC but is
   42.85 + * <i>not</i> adjusted for leap seconds. An interesting source of
   42.86 + * further information is the U.S. Naval Observatory, particularly
   42.87 + * the Directorate of Time at:
   42.88 + * <blockquote><pre>
   42.89 + *     <a href=http://tycho.usno.navy.mil>http://tycho.usno.navy.mil</a>
   42.90 + * </pre></blockquote>
   42.91 + * <p>
   42.92 + * and their definitions of "Systems of Time" at:
   42.93 + * <blockquote><pre>
   42.94 + *     <a href=http://tycho.usno.navy.mil/systime.html>http://tycho.usno.navy.mil/systime.html</a>
   42.95 + * </pre></blockquote>
   42.96 + * <p>
   42.97 + * In all methods of class <code>Date</code> that accept or return
   42.98 + * year, month, date, hours, minutes, and seconds values, the
   42.99 + * following representations are used:
  42.100 + * <ul>
  42.101 + * <li>A year <i>y</i> is represented by the integer
  42.102 + *     <i>y</i>&nbsp;<code>-&nbsp;1900</code>.
  42.103 + * <li>A month is represented by an integer from 0 to 11; 0 is January,
  42.104 + *     1 is February, and so forth; thus 11 is December.
  42.105 + * <li>A date (day of month) is represented by an integer from 1 to 31
  42.106 + *     in the usual manner.
  42.107 + * <li>An hour is represented by an integer from 0 to 23. Thus, the hour
  42.108 + *     from midnight to 1 a.m. is hour 0, and the hour from noon to 1
  42.109 + *     p.m. is hour 12.
  42.110 + * <li>A minute is represented by an integer from 0 to 59 in the usual manner.
  42.111 + * <li>A second is represented by an integer from 0 to 61; the values 60 and
  42.112 + *     61 occur only for leap seconds and even then only in Java
  42.113 + *     implementations that actually track leap seconds correctly. Because
  42.114 + *     of the manner in which leap seconds are currently introduced, it is
  42.115 + *     extremely unlikely that two leap seconds will occur in the same
  42.116 + *     minute, but this specification follows the date and time conventions
  42.117 + *     for ISO C.
  42.118 + * </ul>
  42.119 + * <p>
  42.120 + * In all cases, arguments given to methods for these purposes need
  42.121 + * not fall within the indicated ranges; for example, a date may be
  42.122 + * specified as January 32 and is interpreted as meaning February 1.
  42.123 + *
  42.124 + * @author  James Gosling
  42.125 + * @author  Arthur van Hoff
  42.126 + * @author  Alan Liu
  42.127 + * @see     java.text.DateFormat
  42.128 + * @see     java.util.Calendar
  42.129 + * @see     java.util.TimeZone
  42.130 + * @since   JDK1.0
  42.131 + */
  42.132 +public class Date
  42.133 +    implements java.io.Serializable, Cloneable, Comparable<Date>
  42.134 +{
  42.135 +    private static final BaseCalendar gcal =
  42.136 +                                CalendarSystem.getGregorianCalendar();
  42.137 +    private static BaseCalendar jcal;
  42.138 +
  42.139 +    private transient long fastTime;
  42.140 +
  42.141 +    /*
  42.142 +     * If cdate is null, then fastTime indicates the time in millis.
  42.143 +     * If cdate.isNormalized() is true, then fastTime and cdate are in
  42.144 +     * synch. Otherwise, fastTime is ignored, and cdate indicates the
  42.145 +     * time.
  42.146 +     */
  42.147 +    private transient BaseCalendar.Date cdate;
  42.148 +
  42.149 +    // Initialized just before the value is used. See parse().
  42.150 +    private static int defaultCenturyStart;
  42.151 +
  42.152 +    /* use serialVersionUID from modified java.util.Date for
  42.153 +     * interoperability with JDK1.1. The Date was modified to write
  42.154 +     * and read only the UTC time.
  42.155 +     */
  42.156 +    private static final long serialVersionUID = 7523967970034938905L;
  42.157 +
  42.158 +    /**
  42.159 +     * Allocates a <code>Date</code> object and initializes it so that
  42.160 +     * it represents the time at which it was allocated, measured to the
  42.161 +     * nearest millisecond.
  42.162 +     *
  42.163 +     * @see     java.lang.System#currentTimeMillis()
  42.164 +     */
  42.165 +    public Date() {
  42.166 +        this(System.currentTimeMillis());
  42.167 +    }
  42.168 +
  42.169 +    /**
  42.170 +     * Allocates a <code>Date</code> object and initializes it to
  42.171 +     * represent the specified number of milliseconds since the
  42.172 +     * standard base time known as "the epoch", namely January 1,
  42.173 +     * 1970, 00:00:00 GMT.
  42.174 +     *
  42.175 +     * @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
  42.176 +     * @see     java.lang.System#currentTimeMillis()
  42.177 +     */
  42.178 +    public Date(long date) {
  42.179 +        fastTime = date;
  42.180 +    }
  42.181 +
  42.182 +    /**
  42.183 +     * Allocates a <code>Date</code> object and initializes it so that
  42.184 +     * it represents midnight, local time, at the beginning of the day
  42.185 +     * specified by the <code>year</code>, <code>month</code>, and
  42.186 +     * <code>date</code> arguments.
  42.187 +     *
  42.188 +     * @param   year    the year minus 1900.
  42.189 +     * @param   month   the month between 0-11.
  42.190 +     * @param   date    the day of the month between 1-31.
  42.191 +     * @see     java.util.Calendar
  42.192 +     * @deprecated As of JDK version 1.1,
  42.193 +     * replaced by <code>Calendar.set(year + 1900, month, date)</code>
  42.194 +     * or <code>GregorianCalendar(year + 1900, month, date)</code>.
  42.195 +     */
  42.196 +    @Deprecated
  42.197 +    public Date(int year, int month, int date) {
  42.198 +        this(year, month, date, 0, 0, 0);
  42.199 +    }
  42.200 +
  42.201 +    /**
  42.202 +     * Allocates a <code>Date</code> object and initializes it so that
  42.203 +     * it represents the instant at the start of the minute specified by
  42.204 +     * the <code>year</code>, <code>month</code>, <code>date</code>,
  42.205 +     * <code>hrs</code>, and <code>min</code> arguments, in the local
  42.206 +     * time zone.
  42.207 +     *
  42.208 +     * @param   year    the year minus 1900.
  42.209 +     * @param   month   the month between 0-11.
  42.210 +     * @param   date    the day of the month between 1-31.
  42.211 +     * @param   hrs     the hours between 0-23.
  42.212 +     * @param   min     the minutes between 0-59.
  42.213 +     * @see     java.util.Calendar
  42.214 +     * @deprecated As of JDK version 1.1,
  42.215 +     * replaced by <code>Calendar.set(year + 1900, month, date,
  42.216 +     * hrs, min)</code> or <code>GregorianCalendar(year + 1900,
  42.217 +     * month, date, hrs, min)</code>.
  42.218 +     */
  42.219 +    @Deprecated
  42.220 +    public Date(int year, int month, int date, int hrs, int min) {
  42.221 +        this(year, month, date, hrs, min, 0);
  42.222 +    }
  42.223 +
  42.224 +    /**
  42.225 +     * Allocates a <code>Date</code> object and initializes it so that
  42.226 +     * it represents the instant at the start of the second specified
  42.227 +     * by the <code>year</code>, <code>month</code>, <code>date</code>,
  42.228 +     * <code>hrs</code>, <code>min</code>, and <code>sec</code> arguments,
  42.229 +     * in the local time zone.
  42.230 +     *
  42.231 +     * @param   year    the year minus 1900.
  42.232 +     * @param   month   the month between 0-11.
  42.233 +     * @param   date    the day of the month between 1-31.
  42.234 +     * @param   hrs     the hours between 0-23.
  42.235 +     * @param   min     the minutes between 0-59.
  42.236 +     * @param   sec     the seconds between 0-59.
  42.237 +     * @see     java.util.Calendar
  42.238 +     * @deprecated As of JDK version 1.1,
  42.239 +     * replaced by <code>Calendar.set(year + 1900, month, date,
  42.240 +     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
  42.241 +     * month, date, hrs, min, sec)</code>.
  42.242 +     */
  42.243 +    @Deprecated
  42.244 +    public Date(int year, int month, int date, int hrs, int min, int sec) {
  42.245 +        int y = year + 1900;
  42.246 +        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
  42.247 +        if (month >= 12) {
  42.248 +            y += month / 12;
  42.249 +            month %= 12;
  42.250 +        } else if (month < 0) {
  42.251 +            y += CalendarUtils.floorDivide(month, 12);
  42.252 +            month = CalendarUtils.mod(month, 12);
  42.253 +        }
  42.254 +        BaseCalendar cal = getCalendarSystem(y);
  42.255 +        cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
  42.256 +        cdate.setNormalizedDate(y, month + 1, date).setTimeOfDay(hrs, min, sec, 0);
  42.257 +        getTimeImpl();
  42.258 +        cdate = null;
  42.259 +    }
  42.260 +
  42.261 +    /**
  42.262 +     * Allocates a <code>Date</code> object and initializes it so that
  42.263 +     * it represents the date and time indicated by the string
  42.264 +     * <code>s</code>, which is interpreted as if by the
  42.265 +     * {@link Date#parse} method.
  42.266 +     *
  42.267 +     * @param   s   a string representation of the date.
  42.268 +     * @see     java.text.DateFormat
  42.269 +     * @see     java.util.Date#parse(java.lang.String)
  42.270 +     * @deprecated As of JDK version 1.1,
  42.271 +     * replaced by <code>DateFormat.parse(String s)</code>.
  42.272 +     */
  42.273 +    @Deprecated
  42.274 +    public Date(String s) {
  42.275 +        this(parse(s));
  42.276 +    }
  42.277 +
  42.278 +    /**
  42.279 +     * Return a copy of this object.
  42.280 +     */
  42.281 +    public Object clone() {
  42.282 +        Date d = null;
  42.283 +        try {
  42.284 +            d = (Date)super.clone();
  42.285 +            if (cdate != null) {
  42.286 +                d.cdate = (BaseCalendar.Date) cdate.clone();
  42.287 +            }
  42.288 +        } catch (CloneNotSupportedException e) {} // Won't happen
  42.289 +        return d;
  42.290 +    }
  42.291 +
  42.292 +    /**
  42.293 +     * Determines the date and time based on the arguments. The
  42.294 +     * arguments are interpreted as a year, month, day of the month,
  42.295 +     * hour of the day, minute within the hour, and second within the
  42.296 +     * minute, exactly as for the <tt>Date</tt> constructor with six
  42.297 +     * arguments, except that the arguments are interpreted relative
  42.298 +     * to UTC rather than to the local time zone. The time indicated is
  42.299 +     * returned represented as the distance, measured in milliseconds,
  42.300 +     * of that time from the epoch (00:00:00 GMT on January 1, 1970).
  42.301 +     *
  42.302 +     * @param   year    the year minus 1900.
  42.303 +     * @param   month   the month between 0-11.
  42.304 +     * @param   date    the day of the month between 1-31.
  42.305 +     * @param   hrs     the hours between 0-23.
  42.306 +     * @param   min     the minutes between 0-59.
  42.307 +     * @param   sec     the seconds between 0-59.
  42.308 +     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT for
  42.309 +     *          the date and time specified by the arguments.
  42.310 +     * @see     java.util.Calendar
  42.311 +     * @deprecated As of JDK version 1.1,
  42.312 +     * replaced by <code>Calendar.set(year + 1900, month, date,
  42.313 +     * hrs, min, sec)</code> or <code>GregorianCalendar(year + 1900,
  42.314 +     * month, date, hrs, min, sec)</code>, using a UTC
  42.315 +     * <code>TimeZone</code>, followed by <code>Calendar.getTime().getTime()</code>.
  42.316 +     */
  42.317 +    @Deprecated
  42.318 +    public static long UTC(int year, int month, int date,
  42.319 +                           int hrs, int min, int sec) {
  42.320 +        int y = year + 1900;
  42.321 +        // month is 0-based. So we have to normalize month to support Long.MAX_VALUE.
  42.322 +        if (month >= 12) {
  42.323 +            y += month / 12;
  42.324 +            month %= 12;
  42.325 +        } else if (month < 0) {
  42.326 +            y += CalendarUtils.floorDivide(month, 12);
  42.327 +            month = CalendarUtils.mod(month, 12);
  42.328 +        }
  42.329 +        int m = month + 1;
  42.330 +        BaseCalendar cal = getCalendarSystem(y);
  42.331 +        BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null);
  42.332 +        udate.setNormalizedDate(y, m, date).setTimeOfDay(hrs, min, sec, 0);
  42.333 +
  42.334 +        // Use a Date instance to perform normalization. Its fastTime
  42.335 +        // is the UTC value after the normalization.
  42.336 +        Date d = new Date(0);
  42.337 +        d.normalize(udate);
  42.338 +        return d.fastTime;
  42.339 +    }
  42.340 +
  42.341 +    /**
  42.342 +     * Attempts to interpret the string <tt>s</tt> as a representation
  42.343 +     * of a date and time. If the attempt is successful, the time
  42.344 +     * indicated is returned represented as the distance, measured in
  42.345 +     * milliseconds, of that time from the epoch (00:00:00 GMT on
  42.346 +     * January 1, 1970). If the attempt fails, an
  42.347 +     * <tt>IllegalArgumentException</tt> is thrown.
  42.348 +     * <p>
  42.349 +     * It accepts many syntaxes; in particular, it recognizes the IETF
  42.350 +     * standard date syntax: "Sat, 12 Aug 1995 13:30:00 GMT". It also
  42.351 +     * understands the continental U.S. time-zone abbreviations, but for
  42.352 +     * general use, a time-zone offset should be used: "Sat, 12 Aug 1995
  42.353 +     * 13:30:00 GMT+0430" (4 hours, 30 minutes west of the Greenwich
  42.354 +     * meridian). If no time zone is specified, the local time zone is
  42.355 +     * assumed. GMT and UTC are considered equivalent.
  42.356 +     * <p>
  42.357 +     * The string <tt>s</tt> is processed from left to right, looking for
  42.358 +     * data of interest. Any material in <tt>s</tt> that is within the
  42.359 +     * ASCII parenthesis characters <tt>(</tt> and <tt>)</tt> is ignored.
  42.360 +     * Parentheses may be nested. Otherwise, the only characters permitted
  42.361 +     * within <tt>s</tt> are these ASCII characters:
  42.362 +     * <blockquote><pre>
  42.363 +     * abcdefghijklmnopqrstuvwxyz
  42.364 +     * ABCDEFGHIJKLMNOPQRSTUVWXYZ
  42.365 +     * 0123456789,+-:/</pre></blockquote>
  42.366 +     * and whitespace characters.<p>
  42.367 +     * A consecutive sequence of decimal digits is treated as a decimal
  42.368 +     * number:<ul>
  42.369 +     * <li>If a number is preceded by <tt>+</tt> or <tt>-</tt> and a year
  42.370 +     *     has already been recognized, then the number is a time-zone
  42.371 +     *     offset. If the number is less than 24, it is an offset measured
  42.372 +     *     in hours. Otherwise, it is regarded as an offset in minutes,
  42.373 +     *     expressed in 24-hour time format without punctuation. A
  42.374 +     *     preceding <tt>-</tt> means a westward offset. Time zone offsets
  42.375 +     *     are always relative to UTC (Greenwich). Thus, for example,
  42.376 +     *     <tt>-5</tt> occurring in the string would mean "five hours west
  42.377 +     *     of Greenwich" and <tt>+0430</tt> would mean "four hours and
  42.378 +     *     thirty minutes east of Greenwich." It is permitted for the
  42.379 +     *     string to specify <tt>GMT</tt>, <tt>UT</tt>, or <tt>UTC</tt>
  42.380 +     *     redundantly-for example, <tt>GMT-5</tt> or <tt>utc+0430</tt>.
  42.381 +     * <li>The number is regarded as a year number if one of the
  42.382 +     *     following conditions is true:
  42.383 +     * <ul>
  42.384 +     *     <li>The number is equal to or greater than 70 and followed by a
  42.385 +     *         space, comma, slash, or end of string
  42.386 +     *     <li>The number is less than 70, and both a month and a day of
  42.387 +     *         the month have already been recognized</li>
  42.388 +     * </ul>
  42.389 +     *     If the recognized year number is less than 100, it is
  42.390 +     *     interpreted as an abbreviated year relative to a century of
  42.391 +     *     which dates are within 80 years before and 19 years after
  42.392 +     *     the time when the Date class is initialized.
  42.393 +     *     After adjusting the year number, 1900 is subtracted from
  42.394 +     *     it. For example, if the current year is 1999 then years in
  42.395 +     *     the range 19 to 99 are assumed to mean 1919 to 1999, while
  42.396 +     *     years from 0 to 18 are assumed to mean 2000 to 2018.  Note
  42.397 +     *     that this is slightly different from the interpretation of
  42.398 +     *     years less than 100 that is used in {@link java.text.SimpleDateFormat}.
  42.399 +     * <li>If the number is followed by a colon, it is regarded as an hour,
  42.400 +     *     unless an hour has already been recognized, in which case it is
  42.401 +     *     regarded as a minute.
  42.402 +     * <li>If the number is followed by a slash, it is regarded as a month
  42.403 +     *     (it is decreased by 1 to produce a number in the range <tt>0</tt>
  42.404 +     *     to <tt>11</tt>), unless a month has already been recognized, in
  42.405 +     *     which case it is regarded as a day of the month.
  42.406 +     * <li>If the number is followed by whitespace, a comma, a hyphen, or
  42.407 +     *     end of string, then if an hour has been recognized but not a
  42.408 +     *     minute, it is regarded as a minute; otherwise, if a minute has
  42.409 +     *     been recognized but not a second, it is regarded as a second;
  42.410 +     *     otherwise, it is regarded as a day of the month. </ul><p>
  42.411 +     * A consecutive sequence of letters is regarded as a word and treated
  42.412 +     * as follows:<ul>
  42.413 +     * <li>A word that matches <tt>AM</tt>, ignoring case, is ignored (but
  42.414 +     *     the parse fails if an hour has not been recognized or is less
  42.415 +     *     than <tt>1</tt> or greater than <tt>12</tt>).
  42.416 +     * <li>A word that matches <tt>PM</tt>, ignoring case, adds <tt>12</tt>
  42.417 +     *     to the hour (but the parse fails if an hour has not been
  42.418 +     *     recognized or is less than <tt>1</tt> or greater than <tt>12</tt>).
  42.419 +     * <li>Any word that matches any prefix of <tt>SUNDAY, MONDAY, TUESDAY,
  42.420 +     *     WEDNESDAY, THURSDAY, FRIDAY</tt>, or <tt>SATURDAY</tt>, ignoring
  42.421 +     *     case, is ignored. For example, <tt>sat, Friday, TUE</tt>, and
  42.422 +     *     <tt>Thurs</tt> are ignored.
  42.423 +     * <li>Otherwise, any word that matches any prefix of <tt>JANUARY,
  42.424 +     *     FEBRUARY, MARCH, APRIL, MAY, JUNE, JULY, AUGUST, SEPTEMBER,
  42.425 +     *     OCTOBER, NOVEMBER</tt>, or <tt>DECEMBER</tt>, ignoring case, and
  42.426 +     *     considering them in the order given here, is recognized as
  42.427 +     *     specifying a month and is converted to a number (<tt>0</tt> to
  42.428 +     *     <tt>11</tt>). For example, <tt>aug, Sept, april</tt>, and
  42.429 +     *     <tt>NOV</tt> are recognized as months. So is <tt>Ma</tt>, which
  42.430 +     *     is recognized as <tt>MARCH</tt>, not <tt>MAY</tt>.
  42.431 +     * <li>Any word that matches <tt>GMT, UT</tt>, or <tt>UTC</tt>, ignoring
  42.432 +     *     case, is treated as referring to UTC.
  42.433 +     * <li>Any word that matches <tt>EST, CST, MST</tt>, or <tt>PST</tt>,
  42.434 +     *     ignoring case, is recognized as referring to the time zone in
  42.435 +     *     North America that is five, six, seven, or eight hours west of
  42.436 +     *     Greenwich, respectively. Any word that matches <tt>EDT, CDT,
  42.437 +     *     MDT</tt>, or <tt>PDT</tt>, ignoring case, is recognized as
  42.438 +     *     referring to the same time zone, respectively, during daylight
  42.439 +     *     saving time.</ul><p>
  42.440 +     * Once the entire string s has been scanned, it is converted to a time
  42.441 +     * result in one of two ways. If a time zone or time-zone offset has been
  42.442 +     * recognized, then the year, month, day of month, hour, minute, and
  42.443 +     * second are interpreted in UTC and then the time-zone offset is
  42.444 +     * applied. Otherwise, the year, month, day of month, hour, minute, and
  42.445 +     * second are interpreted in the local time zone.
  42.446 +     *
  42.447 +     * @param   s   a string to be parsed as a date.
  42.448 +     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
  42.449 +     *          represented by the string argument.
  42.450 +     * @see     java.text.DateFormat
  42.451 +     * @deprecated As of JDK version 1.1,
  42.452 +     * replaced by <code>DateFormat.parse(String s)</code>.
  42.453 +     */
  42.454 +    @Deprecated
  42.455 +    public static long parse(String s) {
  42.456 +        int year = Integer.MIN_VALUE;
  42.457 +        int mon = -1;
  42.458 +        int mday = -1;
  42.459 +        int hour = -1;
  42.460 +        int min = -1;
  42.461 +        int sec = -1;
  42.462 +        int millis = -1;
  42.463 +        int c = -1;
  42.464 +        int i = 0;
  42.465 +        int n = -1;
  42.466 +        int wst = -1;
  42.467 +        int tzoffset = -1;
  42.468 +        int prevc = 0;
  42.469 +    syntax:
  42.470 +        {
  42.471 +            if (s == null)
  42.472 +                break syntax;
  42.473 +            int limit = s.length();
  42.474 +            while (i < limit) {
  42.475 +                c = s.charAt(i);
  42.476 +                i++;
  42.477 +                if (c <= ' ' || c == ',')
  42.478 +                    continue;
  42.479 +                if (c == '(') { // skip comments
  42.480 +                    int depth = 1;
  42.481 +                    while (i < limit) {
  42.482 +                        c = s.charAt(i);
  42.483 +                        i++;
  42.484 +                        if (c == '(') depth++;
  42.485 +                        else if (c == ')')
  42.486 +                            if (--depth <= 0)
  42.487 +                                break;
  42.488 +                    }
  42.489 +                    continue;
  42.490 +                }
  42.491 +                if ('0' <= c && c <= '9') {
  42.492 +                    n = c - '0';
  42.493 +                    while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') {
  42.494 +                        n = n * 10 + c - '0';
  42.495 +                        i++;
  42.496 +                    }
  42.497 +                    if (prevc == '+' || prevc == '-' && year != Integer.MIN_VALUE) {
  42.498 +                        // timezone offset
  42.499 +                        if (n < 24)
  42.500 +                            n = n * 60; // EG. "GMT-3"
  42.501 +                        else
  42.502 +                            n = n % 100 + n / 100 * 60; // eg "GMT-0430"
  42.503 +                        if (prevc == '+')   // plus means east of GMT
  42.504 +                            n = -n;
  42.505 +                        if (tzoffset != 0 && tzoffset != -1)
  42.506 +                            break syntax;
  42.507 +                        tzoffset = n;
  42.508 +                    } else if (n >= 70)
  42.509 +                        if (year != Integer.MIN_VALUE)
  42.510 +                            break syntax;
  42.511 +                        else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
  42.512 +                            // year = n < 1900 ? n : n - 1900;
  42.513 +                            year = n;
  42.514 +                        else
  42.515 +                            break syntax;
  42.516 +                    else if (c == ':')
  42.517 +                        if (hour < 0)
  42.518 +                            hour = (byte) n;
  42.519 +                        else if (min < 0)
  42.520 +                            min = (byte) n;
  42.521 +                        else
  42.522 +                            break syntax;
  42.523 +                    else if (c == '/')
  42.524 +                        if (mon < 0)
  42.525 +                            mon = (byte) (n - 1);
  42.526 +                        else if (mday < 0)
  42.527 +                            mday = (byte) n;
  42.528 +                        else
  42.529 +                            break syntax;
  42.530 +                    else if (i < limit && c != ',' && c > ' ' && c != '-')
  42.531 +                        break syntax;
  42.532 +                    else if (hour >= 0 && min < 0)
  42.533 +                        min = (byte) n;
  42.534 +                    else if (min >= 0 && sec < 0)
  42.535 +                        sec = (byte) n;
  42.536 +                    else if (mday < 0)
  42.537 +                        mday = (byte) n;
  42.538 +                    // Handle two-digit years < 70 (70-99 handled above).
  42.539 +                    else if (year == Integer.MIN_VALUE && mon >= 0 && mday >= 0)
  42.540 +                        year = n;
  42.541 +                    else
  42.542 +                        break syntax;
  42.543 +                    prevc = 0;
  42.544 +                } else if (c == '/' || c == ':' || c == '+' || c == '-')
  42.545 +                    prevc = c;
  42.546 +                else {
  42.547 +                    int st = i - 1;
  42.548 +                    while (i < limit) {
  42.549 +                        c = s.charAt(i);
  42.550 +                        if (!('A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'))
  42.551 +                            break;
  42.552 +                        i++;
  42.553 +                    }
  42.554 +                    if (i <= st + 1)
  42.555 +                        break syntax;
  42.556 +                    int k;
  42.557 +                    for (k = wtb.length; --k >= 0;)
  42.558 +                        if (wtb[k].regionMatches(true, 0, s, st, i - st)) {
  42.559 +                            int action = ttb[k];
  42.560 +                            if (action != 0) {
  42.561 +                                if (action == 1) {  // pm
  42.562 +                                    if (hour > 12 || hour < 1)
  42.563 +                                        break syntax;
  42.564 +                                    else if (hour < 12)
  42.565 +                                        hour += 12;
  42.566 +                                } else if (action == 14) {  // am
  42.567 +                                    if (hour > 12 || hour < 1)
  42.568 +                                        break syntax;
  42.569 +                                    else if (hour == 12)
  42.570 +                                        hour = 0;
  42.571 +                                } else if (action <= 13) {  // month!
  42.572 +                                    if (mon < 0)
  42.573 +                                        mon = (byte) (action - 2);
  42.574 +                                    else
  42.575 +                                        break syntax;
  42.576 +                                } else {
  42.577 +                                    tzoffset = action - 10000;
  42.578 +                                }
  42.579 +                            }
  42.580 +                            break;
  42.581 +                        }
  42.582 +                    if (k < 0)
  42.583 +                        break syntax;
  42.584 +                    prevc = 0;
  42.585 +                }
  42.586 +            }
  42.587 +            if (year == Integer.MIN_VALUE || mon < 0 || mday < 0)
  42.588 +                break syntax;
  42.589 +            // Parse 2-digit years within the correct default century.
  42.590 +            if (year < 100) {
  42.591 +                synchronized (Date.class) {
  42.592 +                    if (defaultCenturyStart == 0) {
  42.593 +                        defaultCenturyStart = gcal.getCalendarDate().getYear() - 80;
  42.594 +                    }
  42.595 +                }
  42.596 +                year += (defaultCenturyStart / 100) * 100;
  42.597 +                if (year < defaultCenturyStart) year += 100;
  42.598 +            }
  42.599 +            if (sec < 0)
  42.600 +                sec = 0;
  42.601 +            if (min < 0)
  42.602 +                min = 0;
  42.603 +            if (hour < 0)
  42.604 +                hour = 0;
  42.605 +            BaseCalendar cal = getCalendarSystem(year);
  42.606 +            if (tzoffset == -1)  { // no time zone specified, have to use local
  42.607 +                BaseCalendar.Date ldate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.getDefaultRef());
  42.608 +                ldate.setDate(year, mon + 1, mday);
  42.609 +                ldate.setTimeOfDay(hour, min, sec, 0);
  42.610 +                return cal.getTime(ldate);
  42.611 +            }
  42.612 +            BaseCalendar.Date udate = (BaseCalendar.Date) cal.newCalendarDate(null); // no time zone
  42.613 +            udate.setDate(year, mon + 1, mday);
  42.614 +            udate.setTimeOfDay(hour, min, sec, 0);
  42.615 +            return cal.getTime(udate) + tzoffset * (60 * 1000);
  42.616 +        }
  42.617 +        // syntax error
  42.618 +        throw new IllegalArgumentException();
  42.619 +    }
  42.620 +    private final static String wtb[] = {
  42.621 +        "am", "pm",
  42.622 +        "monday", "tuesday", "wednesday", "thursday", "friday",
  42.623 +        "saturday", "sunday",
  42.624 +        "january", "february", "march", "april", "may", "june",
  42.625 +        "july", "august", "september", "october", "november", "december",
  42.626 +        "gmt", "ut", "utc", "est", "edt", "cst", "cdt",
  42.627 +        "mst", "mdt", "pst", "pdt"
  42.628 +    };
  42.629 +    private final static int ttb[] = {
  42.630 +        14, 1, 0, 0, 0, 0, 0, 0, 0,
  42.631 +        2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
  42.632 +        10000 + 0, 10000 + 0, 10000 + 0,    // GMT/UT/UTC
  42.633 +        10000 + 5 * 60, 10000 + 4 * 60,     // EST/EDT
  42.634 +        10000 + 6 * 60, 10000 + 5 * 60,     // CST/CDT
  42.635 +        10000 + 7 * 60, 10000 + 6 * 60,     // MST/MDT
  42.636 +        10000 + 8 * 60, 10000 + 7 * 60      // PST/PDT
  42.637 +    };
  42.638 +
  42.639 +    /**
  42.640 +     * Returns a value that is the result of subtracting 1900 from the
  42.641 +     * year that contains or begins with the instant in time represented
  42.642 +     * by this <code>Date</code> object, as interpreted in the local
  42.643 +     * time zone.
  42.644 +     *
  42.645 +     * @return  the year represented by this date, minus 1900.
  42.646 +     * @see     java.util.Calendar
  42.647 +     * @deprecated As of JDK version 1.1,
  42.648 +     * replaced by <code>Calendar.get(Calendar.YEAR) - 1900</code>.
  42.649 +     */
  42.650 +    @Deprecated
  42.651 +    public int getYear() {
  42.652 +        return normalize().getYear() - 1900;
  42.653 +    }
  42.654 +
  42.655 +    /**
  42.656 +     * Sets the year of this <tt>Date</tt> object to be the specified
  42.657 +     * value plus 1900. This <code>Date</code> object is modified so
  42.658 +     * that it represents a point in time within the specified year,
  42.659 +     * with the month, date, hour, minute, and second the same as
  42.660 +     * before, as interpreted in the local time zone. (Of course, if
  42.661 +     * the date was February 29, for example, and the year is set to a
  42.662 +     * non-leap year, then the new date will be treated as if it were
  42.663 +     * on March 1.)
  42.664 +     *
  42.665 +     * @param   year    the year value.
  42.666 +     * @see     java.util.Calendar
  42.667 +     * @deprecated As of JDK version 1.1,
  42.668 +     * replaced by <code>Calendar.set(Calendar.YEAR, year + 1900)</code>.
  42.669 +     */
  42.670 +    @Deprecated
  42.671 +    public void setYear(int year) {
  42.672 +        getCalendarDate().setNormalizedYear(year + 1900);
  42.673 +    }
  42.674 +
  42.675 +    /**
  42.676 +     * Returns a number representing the month that contains or begins
  42.677 +     * with the instant in time represented by this <tt>Date</tt> object.
  42.678 +     * The value returned is between <code>0</code> and <code>11</code>,
  42.679 +     * with the value <code>0</code> representing January.
  42.680 +     *
  42.681 +     * @return  the month represented by this date.
  42.682 +     * @see     java.util.Calendar
  42.683 +     * @deprecated As of JDK version 1.1,
  42.684 +     * replaced by <code>Calendar.get(Calendar.MONTH)</code>.
  42.685 +     */
  42.686 +    @Deprecated
  42.687 +    public int getMonth() {
  42.688 +        return normalize().getMonth() - 1; // adjust 1-based to 0-based
  42.689 +    }
  42.690 +
  42.691 +    /**
  42.692 +     * Sets the month of this date to the specified value. This
  42.693 +     * <tt>Date</tt> object is modified so that it represents a point
  42.694 +     * in time within the specified month, with the year, date, hour,
  42.695 +     * minute, and second the same as before, as interpreted in the
  42.696 +     * local time zone. If the date was October 31, for example, and
  42.697 +     * the month is set to June, then the new date will be treated as
  42.698 +     * if it were on July 1, because June has only 30 days.
  42.699 +     *
  42.700 +     * @param   month   the month value between 0-11.
  42.701 +     * @see     java.util.Calendar
  42.702 +     * @deprecated As of JDK version 1.1,
  42.703 +     * replaced by <code>Calendar.set(Calendar.MONTH, int month)</code>.
  42.704 +     */
  42.705 +    @Deprecated
  42.706 +    public void setMonth(int month) {
  42.707 +        int y = 0;
  42.708 +        if (month >= 12) {
  42.709 +            y = month / 12;
  42.710 +            month %= 12;
  42.711 +        } else if (month < 0) {
  42.712 +            y = CalendarUtils.floorDivide(month, 12);
  42.713 +            month = CalendarUtils.mod(month, 12);
  42.714 +        }
  42.715 +        BaseCalendar.Date d = getCalendarDate();
  42.716 +        if (y != 0) {
  42.717 +            d.setNormalizedYear(d.getNormalizedYear() + y);
  42.718 +        }
  42.719 +        d.setMonth(month + 1); // adjust 0-based to 1-based month numbering
  42.720 +    }
  42.721 +
  42.722 +    /**
  42.723 +     * Returns the day of the month represented by this <tt>Date</tt> object.
  42.724 +     * The value returned is between <code>1</code> and <code>31</code>
  42.725 +     * representing the day of the month that contains or begins with the
  42.726 +     * instant in time represented by this <tt>Date</tt> object, as
  42.727 +     * interpreted in the local time zone.
  42.728 +     *
  42.729 +     * @return  the day of the month represented by this date.
  42.730 +     * @see     java.util.Calendar
  42.731 +     * @deprecated As of JDK version 1.1,
  42.732 +     * replaced by <code>Calendar.get(Calendar.DAY_OF_MONTH)</code>.
  42.733 +     * @deprecated
  42.734 +     */
  42.735 +    @Deprecated
  42.736 +    public int getDate() {
  42.737 +        return normalize().getDayOfMonth();
  42.738 +    }
  42.739 +
  42.740 +    /**
  42.741 +     * Sets the day of the month of this <tt>Date</tt> object to the
  42.742 +     * specified value. This <tt>Date</tt> object is modified so that
  42.743 +     * it represents a point in time within the specified day of the
  42.744 +     * month, with the year, month, hour, minute, and second the same
  42.745 +     * as before, as interpreted in the local time zone. If the date
  42.746 +     * was April 30, for example, and the date is set to 31, then it
  42.747 +     * will be treated as if it were on May 1, because April has only
  42.748 +     * 30 days.
  42.749 +     *
  42.750 +     * @param   date   the day of the month value between 1-31.
  42.751 +     * @see     java.util.Calendar
  42.752 +     * @deprecated As of JDK version 1.1,
  42.753 +     * replaced by <code>Calendar.set(Calendar.DAY_OF_MONTH, int date)</code>.
  42.754 +     */
  42.755 +    @Deprecated
  42.756 +    public void setDate(int date) {
  42.757 +        getCalendarDate().setDayOfMonth(date);
  42.758 +    }
  42.759 +
  42.760 +    /**
  42.761 +     * Returns the day of the week represented by this date. The
  42.762 +     * returned value (<tt>0</tt> = Sunday, <tt>1</tt> = Monday,
  42.763 +     * <tt>2</tt> = Tuesday, <tt>3</tt> = Wednesday, <tt>4</tt> =
  42.764 +     * Thursday, <tt>5</tt> = Friday, <tt>6</tt> = Saturday)
  42.765 +     * represents the day of the week that contains or begins with
  42.766 +     * the instant in time represented by this <tt>Date</tt> object,
  42.767 +     * as interpreted in the local time zone.
  42.768 +     *
  42.769 +     * @return  the day of the week represented by this date.
  42.770 +     * @see     java.util.Calendar
  42.771 +     * @deprecated As of JDK version 1.1,
  42.772 +     * replaced by <code>Calendar.get(Calendar.DAY_OF_WEEK)</code>.
  42.773 +     */
  42.774 +    @Deprecated
  42.775 +    public int getDay() {
  42.776 +        return normalize().getDayOfWeek() - gcal.SUNDAY;
  42.777 +    }
  42.778 +
  42.779 +    /**
  42.780 +     * Returns the hour represented by this <tt>Date</tt> object. The
  42.781 +     * returned value is a number (<tt>0</tt> through <tt>23</tt>)
  42.782 +     * representing the hour within the day that contains or begins
  42.783 +     * with the instant in time represented by this <tt>Date</tt>
  42.784 +     * object, as interpreted in the local time zone.
  42.785 +     *
  42.786 +     * @return  the hour represented by this date.
  42.787 +     * @see     java.util.Calendar
  42.788 +     * @deprecated As of JDK version 1.1,
  42.789 +     * replaced by <code>Calendar.get(Calendar.HOUR_OF_DAY)</code>.
  42.790 +     */
  42.791 +    @Deprecated
  42.792 +    public int getHours() {
  42.793 +        return normalize().getHours();
  42.794 +    }
  42.795 +
  42.796 +    /**
  42.797 +     * Sets the hour of this <tt>Date</tt> object to the specified value.
  42.798 +     * This <tt>Date</tt> object is modified so that it represents a point
  42.799 +     * in time within the specified hour of the day, with the year, month,
  42.800 +     * date, minute, and second the same as before, as interpreted in the
  42.801 +     * local time zone.
  42.802 +     *
  42.803 +     * @param   hours   the hour value.
  42.804 +     * @see     java.util.Calendar
  42.805 +     * @deprecated As of JDK version 1.1,
  42.806 +     * replaced by <code>Calendar.set(Calendar.HOUR_OF_DAY, int hours)</code>.
  42.807 +     */
  42.808 +    @Deprecated
  42.809 +    public void setHours(int hours) {
  42.810 +        getCalendarDate().setHours(hours);
  42.811 +    }
  42.812 +
  42.813 +    /**
  42.814 +     * Returns the number of minutes past the hour represented by this date,
  42.815 +     * as interpreted in the local time zone.
  42.816 +     * The value returned is between <code>0</code> and <code>59</code>.
  42.817 +     *
  42.818 +     * @return  the number of minutes past the hour represented by this date.
  42.819 +     * @see     java.util.Calendar
  42.820 +     * @deprecated As of JDK version 1.1,
  42.821 +     * replaced by <code>Calendar.get(Calendar.MINUTE)</code>.
  42.822 +     */
  42.823 +    @Deprecated
  42.824 +    public int getMinutes() {
  42.825 +        return normalize().getMinutes();
  42.826 +    }
  42.827 +
  42.828 +    /**
  42.829 +     * Sets the minutes of this <tt>Date</tt> object to the specified value.
  42.830 +     * This <tt>Date</tt> object is modified so that it represents a point
  42.831 +     * in time within the specified minute of the hour, with the year, month,
  42.832 +     * date, hour, and second the same as before, as interpreted in the
  42.833 +     * local time zone.
  42.834 +     *
  42.835 +     * @param   minutes   the value of the minutes.
  42.836 +     * @see     java.util.Calendar
  42.837 +     * @deprecated As of JDK version 1.1,
  42.838 +     * replaced by <code>Calendar.set(Calendar.MINUTE, int minutes)</code>.
  42.839 +     */
  42.840 +    @Deprecated
  42.841 +    public void setMinutes(int minutes) {
  42.842 +        getCalendarDate().setMinutes(minutes);
  42.843 +    }
  42.844 +
  42.845 +    /**
  42.846 +     * Returns the number of seconds past the minute represented by this date.
  42.847 +     * The value returned is between <code>0</code> and <code>61</code>. The
  42.848 +     * values <code>60</code> and <code>61</code> can only occur on those
  42.849 +     * Java Virtual Machines that take leap seconds into account.
  42.850 +     *
  42.851 +     * @return  the number of seconds past the minute represented by this date.
  42.852 +     * @see     java.util.Calendar
  42.853 +     * @deprecated As of JDK version 1.1,
  42.854 +     * replaced by <code>Calendar.get(Calendar.SECOND)</code>.
  42.855 +     */
  42.856 +    @Deprecated
  42.857 +    public int getSeconds() {
  42.858 +        return normalize().getSeconds();
  42.859 +    }
  42.860 +
  42.861 +    /**
  42.862 +     * Sets the seconds of this <tt>Date</tt> to the specified value.
  42.863 +     * This <tt>Date</tt> object is modified so that it represents a
  42.864 +     * point in time within the specified second of the minute, with
  42.865 +     * the year, month, date, hour, and minute the same as before, as
  42.866 +     * interpreted in the local time zone.
  42.867 +     *
  42.868 +     * @param   seconds   the seconds value.
  42.869 +     * @see     java.util.Calendar
  42.870 +     * @deprecated As of JDK version 1.1,
  42.871 +     * replaced by <code>Calendar.set(Calendar.SECOND, int seconds)</code>.
  42.872 +     */
  42.873 +    @Deprecated
  42.874 +    public void setSeconds(int seconds) {
  42.875 +        getCalendarDate().setSeconds(seconds);
  42.876 +    }
  42.877 +
  42.878 +    /**
  42.879 +     * Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
  42.880 +     * represented by this <tt>Date</tt> object.
  42.881 +     *
  42.882 +     * @return  the number of milliseconds since January 1, 1970, 00:00:00 GMT
  42.883 +     *          represented by this date.
  42.884 +     */
  42.885 +    public long getTime() {
  42.886 +        return getTimeImpl();
  42.887 +    }
  42.888 +
  42.889 +    private final long getTimeImpl() {
  42.890 +        if (cdate != null && !cdate.isNormalized()) {
  42.891 +            normalize();
  42.892 +        }
  42.893 +        return fastTime;
  42.894 +    }
  42.895 +
  42.896 +    /**
  42.897 +     * Sets this <code>Date</code> object to represent a point in time that is
  42.898 +     * <code>time</code> milliseconds after January 1, 1970 00:00:00 GMT.
  42.899 +     *
  42.900 +     * @param   time   the number of milliseconds.
  42.901 +     */
  42.902 +    public void setTime(long time) {
  42.903 +        fastTime = time;
  42.904 +        cdate = null;
  42.905 +    }
  42.906 +
  42.907 +    /**
  42.908 +     * Tests if this date is before the specified date.
  42.909 +     *
  42.910 +     * @param   when   a date.
  42.911 +     * @return  <code>true</code> if and only if the instant of time
  42.912 +     *            represented by this <tt>Date</tt> object is strictly
  42.913 +     *            earlier than the instant represented by <tt>when</tt>;
  42.914 +     *          <code>false</code> otherwise.
  42.915 +     * @exception NullPointerException if <code>when</code> is null.
  42.916 +     */
  42.917 +    public boolean before(Date when) {
  42.918 +        return getMillisOf(this) < getMillisOf(when);
  42.919 +    }
  42.920 +
  42.921 +    /**
  42.922 +     * Tests if this date is after the specified date.
  42.923 +     *
  42.924 +     * @param   when   a date.
  42.925 +     * @return  <code>true</code> if and only if the instant represented
  42.926 +     *          by this <tt>Date</tt> object is strictly later than the
  42.927 +     *          instant represented by <tt>when</tt>;
  42.928 +     *          <code>false</code> otherwise.
  42.929 +     * @exception NullPointerException if <code>when</code> is null.
  42.930 +     */
  42.931 +    public boolean after(Date when) {
  42.932 +        return getMillisOf(this) > getMillisOf(when);
  42.933 +    }
  42.934 +
  42.935 +    /**
  42.936 +     * Compares two dates for equality.
  42.937 +     * The result is <code>true</code> if and only if the argument is
  42.938 +     * not <code>null</code> and is a <code>Date</code> object that
  42.939 +     * represents the same point in time, to the millisecond, as this object.
  42.940 +     * <p>
  42.941 +     * Thus, two <code>Date</code> objects are equal if and only if the
  42.942 +     * <code>getTime</code> method returns the same <code>long</code>
  42.943 +     * value for both.
  42.944 +     *
  42.945 +     * @param   obj   the object to compare with.
  42.946 +     * @return  <code>true</code> if the objects are the same;
  42.947 +     *          <code>false</code> otherwise.
  42.948 +     * @see     java.util.Date#getTime()
  42.949 +     */
  42.950 +    public boolean equals(Object obj) {
  42.951 +        return obj instanceof Date && getTime() == ((Date) obj).getTime();
  42.952 +    }
  42.953 +
  42.954 +    /**
  42.955 +     * Returns the millisecond value of this <code>Date</code> object
  42.956 +     * without affecting its internal state.
  42.957 +     */
  42.958 +    static final long getMillisOf(Date date) {
  42.959 +        if (date.cdate == null || date.cdate.isNormalized()) {
  42.960 +            return date.fastTime;
  42.961 +        }
  42.962 +        BaseCalendar.Date d = (BaseCalendar.Date) date.cdate.clone();
  42.963 +        return gcal.getTime(d);
  42.964 +    }
  42.965 +
  42.966 +    /**
  42.967 +     * Compares two Dates for ordering.
  42.968 +     *
  42.969 +     * @param   anotherDate   the <code>Date</code> to be compared.
  42.970 +     * @return  the value <code>0</code> if the argument Date is equal to
  42.971 +     *          this Date; a value less than <code>0</code> if this Date
  42.972 +     *          is before the Date argument; and a value greater than
  42.973 +     *      <code>0</code> if this Date is after the Date argument.
  42.974 +     * @since   1.2
  42.975 +     * @exception NullPointerException if <code>anotherDate</code> is null.
  42.976 +     */
  42.977 +    public int compareTo(Date anotherDate) {
  42.978 +        long thisTime = getMillisOf(this);
  42.979 +        long anotherTime = getMillisOf(anotherDate);
  42.980 +        return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
  42.981 +    }
  42.982 +
  42.983 +    /**
  42.984 +     * Returns a hash code value for this object. The result is the
  42.985 +     * exclusive OR of the two halves of the primitive <tt>long</tt>
  42.986 +     * value returned by the {@link Date#getTime}
  42.987 +     * method. That is, the hash code is the value of the expression:
  42.988 +     * <blockquote><pre>
  42.989 +     * (int)(this.getTime()^(this.getTime() >>> 32))</pre></blockquote>
  42.990 +     *
  42.991 +     * @return  a hash code value for this object.
  42.992 +     */
  42.993 +    public int hashCode() {
  42.994 +        long ht = this.getTime();
  42.995 +        return (int) ht ^ (int) (ht >> 32);
  42.996 +    }
  42.997 +
  42.998 +    /**
  42.999 +     * Converts this <code>Date</code> object to a <code>String</code>
 42.1000 +     * of the form:
 42.1001 +     * <blockquote><pre>
 42.1002 +     * dow mon dd hh:mm:ss zzz yyyy</pre></blockquote>
 42.1003 +     * where:<ul>
 42.1004 +     * <li><tt>dow</tt> is the day of the week (<tt>Sun, Mon, Tue, Wed,
 42.1005 +     *     Thu, Fri, Sat</tt>).
 42.1006 +     * <li><tt>mon</tt> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun,
 42.1007 +     *     Jul, Aug, Sep, Oct, Nov, Dec</tt>).
 42.1008 +     * <li><tt>dd</tt> is the day of the month (<tt>01</tt> through
 42.1009 +     *     <tt>31</tt>), as two decimal digits.
 42.1010 +     * <li><tt>hh</tt> is the hour of the day (<tt>00</tt> through
 42.1011 +     *     <tt>23</tt>), as two decimal digits.
 42.1012 +     * <li><tt>mm</tt> is the minute within the hour (<tt>00</tt> through
 42.1013 +     *     <tt>59</tt>), as two decimal digits.
 42.1014 +     * <li><tt>ss</tt> is the second within the minute (<tt>00</tt> through
 42.1015 +     *     <tt>61</tt>, as two decimal digits.
 42.1016 +     * <li><tt>zzz</tt> is the time zone (and may reflect daylight saving
 42.1017 +     *     time). Standard time zone abbreviations include those
 42.1018 +     *     recognized by the method <tt>parse</tt>. If time zone
 42.1019 +     *     information is not available, then <tt>zzz</tt> is empty -
 42.1020 +     *     that is, it consists of no characters at all.
 42.1021 +     * <li><tt>yyyy</tt> is the year, as four decimal digits.
 42.1022 +     * </ul>
 42.1023 +     *
 42.1024 +     * @return  a string representation of this date.
 42.1025 +     * @see     java.util.Date#toLocaleString()
 42.1026 +     * @see     java.util.Date#toGMTString()
 42.1027 +     */
 42.1028 +    public String toString() {
 42.1029 +        // "EEE MMM dd HH:mm:ss zzz yyyy";
 42.1030 +        BaseCalendar.Date date = normalize();
 42.1031 +        StringBuilder sb = new StringBuilder(28);
 42.1032 +        int index = date.getDayOfWeek();
 42.1033 +        if (index == gcal.SUNDAY) {
 42.1034 +            index = 8;
 42.1035 +        }
 42.1036 +        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
 42.1037 +        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
 42.1038 +        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd
 42.1039 +
 42.1040 +        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
 42.1041 +        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
 42.1042 +        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
 42.1043 +        TimeZone zi = date.getZone();
 42.1044 +        if (zi != null) {
 42.1045 +            sb.append(zi.getDisplayName(date.isDaylightTime(), zi.SHORT, Locale.US)); // zzz
 42.1046 +        } else {
 42.1047 +            sb.append("GMT");
 42.1048 +        }
 42.1049 +        sb.append(' ').append(date.getYear());  // yyyy
 42.1050 +        return sb.toString();
 42.1051 +    }
 42.1052 +
 42.1053 +    /**
 42.1054 +     * Converts the given name to its 3-letter abbreviation (e.g.,
 42.1055 +     * "monday" -> "Mon") and stored the abbreviation in the given
 42.1056 +     * <code>StringBuilder</code>.
 42.1057 +     */
 42.1058 +    private static final StringBuilder convertToAbbr(StringBuilder sb, String name) {
 42.1059 +        sb.append(Character.toUpperCase(name.charAt(0)));
 42.1060 +        sb.append(name.charAt(1)).append(name.charAt(2));
 42.1061 +        return sb;
 42.1062 +    }
 42.1063 +
 42.1064 +    /**
 42.1065 +     * Creates a string representation of this <tt>Date</tt> object in an
 42.1066 +     * implementation-dependent form. The intent is that the form should
 42.1067 +     * be familiar to the user of the Java application, wherever it may
 42.1068 +     * happen to be running. The intent is comparable to that of the
 42.1069 +     * "<code>%c</code>" format supported by the <code>strftime()</code>
 42.1070 +     * function of ISO&nbsp;C.
 42.1071 +     *
 42.1072 +     * @return  a string representation of this date, using the locale
 42.1073 +     *          conventions.
 42.1074 +     * @see     java.text.DateFormat
 42.1075 +     * @see     java.util.Date#toString()
 42.1076 +     * @see     java.util.Date#toGMTString()
 42.1077 +     * @deprecated As of JDK version 1.1,
 42.1078 +     * replaced by <code>DateFormat.format(Date date)</code>.
 42.1079 +     */
 42.1080 +    @Deprecated
 42.1081 +    public String toLocaleString() {
 42.1082 +        DateFormat formatter = DateFormat.getDateTimeInstance();
 42.1083 +        return formatter.format(this);
 42.1084 +    }
 42.1085 +
 42.1086 +    /**
 42.1087 +     * Creates a string representation of this <tt>Date</tt> object of
 42.1088 +     * the form:
 42.1089 +     * <blockquote<pre>
 42.1090 +     * d mon yyyy hh:mm:ss GMT</pre></blockquote>
 42.1091 +     * where:<ul>
 42.1092 +     * <li><i>d</i> is the day of the month (<tt>1</tt> through <tt>31</tt>),
 42.1093 +     *     as one or two decimal digits.
 42.1094 +     * <li><i>mon</i> is the month (<tt>Jan, Feb, Mar, Apr, May, Jun, Jul,
 42.1095 +     *     Aug, Sep, Oct, Nov, Dec</tt>).
 42.1096 +     * <li><i>yyyy</i> is the year, as four decimal digits.
 42.1097 +     * <li><i>hh</i> is the hour of the day (<tt>00</tt> through <tt>23</tt>),
 42.1098 +     *     as two decimal digits.
 42.1099 +     * <li><i>mm</i> is the minute within the hour (<tt>00</tt> through
 42.1100 +     *     <tt>59</tt>), as two decimal digits.
 42.1101 +     * <li><i>ss</i> is the second within the minute (<tt>00</tt> through
 42.1102 +     *     <tt>61</tt>), as two decimal digits.
 42.1103 +     * <li><i>GMT</i> is exactly the ASCII letters "<tt>GMT</tt>" to indicate
 42.1104 +     *     Greenwich Mean Time.
 42.1105 +     * </ul><p>
 42.1106 +     * The result does not depend on the local time zone.
 42.1107 +     *
 42.1108 +     * @return  a string representation of this date, using the Internet GMT
 42.1109 +     *          conventions.
 42.1110 +     * @see     java.text.DateFormat
 42.1111 +     * @see     java.util.Date#toString()
 42.1112 +     * @see     java.util.Date#toLocaleString()
 42.1113 +     * @deprecated As of JDK version 1.1,
 42.1114 +     * replaced by <code>DateFormat.format(Date date)</code>, using a
 42.1115 +     * GMT <code>TimeZone</code>.
 42.1116 +     */
 42.1117 +    @Deprecated
 42.1118 +    public String toGMTString() {
 42.1119 +        // d MMM yyyy HH:mm:ss 'GMT'
 42.1120 +        long t = getTime();
 42.1121 +        BaseCalendar cal = getCalendarSystem(t);
 42.1122 +        BaseCalendar.Date date =
 42.1123 +            (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
 42.1124 +        StringBuilder sb = new StringBuilder(32);
 42.1125 +        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
 42.1126 +        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
 42.1127 +        sb.append(date.getYear()).append(' ');                            // yyyy
 42.1128 +        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
 42.1129 +        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
 42.1130 +        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
 42.1131 +        sb.append(" GMT");                                                // ' GMT'
 42.1132 +        return sb.toString();
 42.1133 +    }
 42.1134 +
 42.1135 +    /**
 42.1136 +     * Returns the offset, measured in minutes, for the local time zone
 42.1137 +     * relative to UTC that is appropriate for the time represented by
 42.1138 +     * this <code>Date</code> object.
 42.1139 +     * <p>
 42.1140 +     * For example, in Massachusetts, five time zones west of Greenwich:
 42.1141 +     * <blockquote><pre>
 42.1142 +     * new Date(96, 1, 14).getTimezoneOffset() returns 300</pre></blockquote>
 42.1143 +     * because on February 14, 1996, standard time (Eastern Standard Time)
 42.1144 +     * is in use, which is offset five hours from UTC; but:
 42.1145 +     * <blockquote><pre>
 42.1146 +     * new Date(96, 5, 1).getTimezoneOffset() returns 240</pre></blockquote>
 42.1147 +     * because on June 1, 1996, daylight saving time (Eastern Daylight Time)
 42.1148 +     * is in use, which is offset only four hours from UTC.<p>
 42.1149 +     * This method produces the same result as if it computed:
 42.1150 +     * <blockquote><pre>
 42.1151 +     * (this.getTime() - UTC(this.getYear(),
 42.1152 +     *                       this.getMonth(),
 42.1153 +     *                       this.getDate(),
 42.1154 +     *                       this.getHours(),
 42.1155 +     *                       this.getMinutes(),
 42.1156 +     *                       this.getSeconds())) / (60 * 1000)
 42.1157 +     * </pre></blockquote>
 42.1158 +     *
 42.1159 +     * @return  the time-zone offset, in minutes, for the current time zone.
 42.1160 +     * @see     java.util.Calendar#ZONE_OFFSET
 42.1161 +     * @see     java.util.Calendar#DST_OFFSET
 42.1162 +     * @see     java.util.TimeZone#getDefault
 42.1163 +     * @deprecated As of JDK version 1.1,
 42.1164 +     * replaced by <code>-(Calendar.get(Calendar.ZONE_OFFSET) +
 42.1165 +     * Calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)</code>.
 42.1166 +     */
 42.1167 +    @Deprecated
 42.1168 +    public int getTimezoneOffset() {
 42.1169 +        int zoneOffset;
 42.1170 +        if (cdate == null) {
 42.1171 +            TimeZone tz = TimeZone.getDefaultRef();
 42.1172 +            if (tz instanceof ZoneInfo) {
 42.1173 +                zoneOffset = ((ZoneInfo)tz).getOffsets(fastTime, null);
 42.1174 +            } else {
 42.1175 +                zoneOffset = tz.getOffset(fastTime);
 42.1176 +            }
 42.1177 +        } else {
 42.1178 +            normalize();
 42.1179 +            zoneOffset = cdate.getZoneOffset();
 42.1180 +        }
 42.1181 +        return -zoneOffset/60000;  // convert to minutes
 42.1182 +    }
 42.1183 +
 42.1184 +    private final BaseCalendar.Date getCalendarDate() {
 42.1185 +        if (cdate == null) {
 42.1186 +            BaseCalendar cal = getCalendarSystem(fastTime);
 42.1187 +            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
 42.1188 +                                                            TimeZone.getDefaultRef());
 42.1189 +        }
 42.1190 +        return cdate;
 42.1191 +    }
 42.1192 +
 42.1193 +    private final BaseCalendar.Date normalize() {
 42.1194 +        if (cdate == null) {
 42.1195 +            BaseCalendar cal = getCalendarSystem(fastTime);
 42.1196 +            cdate = (BaseCalendar.Date) cal.getCalendarDate(fastTime,
 42.1197 +                                                            TimeZone.getDefaultRef());
 42.1198 +            return cdate;
 42.1199 +        }
 42.1200 +
 42.1201 +        // Normalize cdate with the TimeZone in cdate first. This is
 42.1202 +        // required for the compatible behavior.
 42.1203 +        if (!cdate.isNormalized()) {
 42.1204 +            cdate = normalize(cdate);
 42.1205 +        }
 42.1206 +
 42.1207 +        // If the default TimeZone has changed, then recalculate the
 42.1208 +        // fields with the new TimeZone.
 42.1209 +        TimeZone tz = TimeZone.getDefaultRef();
 42.1210 +        if (tz != cdate.getZone()) {
 42.1211 +            cdate.setZone(tz);
 42.1212 +            CalendarSystem cal = getCalendarSystem(cdate);
 42.1213 +            cal.getCalendarDate(fastTime, cdate);
 42.1214 +        }
 42.1215 +        return cdate;
 42.1216 +    }
 42.1217 +
 42.1218 +    // fastTime and the returned data are in sync upon return.
 42.1219 +    private final BaseCalendar.Date normalize(BaseCalendar.Date date) {
 42.1220 +        int y = date.getNormalizedYear();
 42.1221 +        int m = date.getMonth();
 42.1222 +        int d = date.getDayOfMonth();
 42.1223 +        int hh = date.getHours();
 42.1224 +        int mm = date.getMinutes();
 42.1225 +        int ss = date.getSeconds();
 42.1226 +        int ms = date.getMillis();
 42.1227 +        TimeZone tz = date.getZone();
 42.1228 +
 42.1229 +        // If the specified year can't be handled using a long value
 42.1230 +        // in milliseconds, GregorianCalendar is used for full
 42.1231 +        // compatibility with underflow and overflow. This is required
 42.1232 +        // by some JCK tests. The limits are based max year values -
 42.1233 +        // years that can be represented by max values of d, hh, mm,
 42.1234 +        // ss and ms. Also, let GregorianCalendar handle the default
 42.1235 +        // cutover year so that we don't need to worry about the
 42.1236 +        // transition here.
 42.1237 +        if (y == 1582 || y > 280000000 || y < -280000000) {
 42.1238 +            if (tz == null) {
 42.1239 +                tz = TimeZone.getTimeZone("GMT");
 42.1240 +            }
 42.1241 +            GregorianCalendar gc = new GregorianCalendar(tz);
 42.1242 +            gc.clear();
 42.1243 +            gc.set(gc.MILLISECOND, ms);
 42.1244 +            gc.set(y, m-1, d, hh, mm, ss);
 42.1245 +            fastTime = gc.getTimeInMillis();
 42.1246 +            BaseCalendar cal = getCalendarSystem(fastTime);
 42.1247 +            date = (BaseCalendar.Date) cal.getCalendarDate(fastTime, tz);
 42.1248 +            return date;
 42.1249 +        }
 42.1250 +
 42.1251 +        BaseCalendar cal = getCalendarSystem(y);
 42.1252 +        if (cal != getCalendarSystem(date)) {
 42.1253 +            date = (BaseCalendar.Date) cal.newCalendarDate(tz);
 42.1254 +            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
 42.1255 +        }
 42.1256 +        // Perform the GregorianCalendar-style normalization.
 42.1257 +        fastTime = cal.getTime(date);
 42.1258 +
 42.1259 +        // In case the normalized date requires the other calendar
 42.1260 +        // system, we need to recalculate it using the other one.
 42.1261 +        BaseCalendar ncal = getCalendarSystem(fastTime);
 42.1262 +        if (ncal != cal) {
 42.1263 +            date = (BaseCalendar.Date) ncal.newCalendarDate(tz);
 42.1264 +            date.setNormalizedDate(y, m, d).setTimeOfDay(hh, mm, ss, ms);
 42.1265 +            fastTime = ncal.getTime(date);
 42.1266 +        }
 42.1267 +        return date;
 42.1268 +    }
 42.1269 +
 42.1270 +    /**
 42.1271 +     * Returns the Gregorian or Julian calendar system to use with the
 42.1272 +     * given date. Use Gregorian from October 15, 1582.
 42.1273 +     *
 42.1274 +     * @param year normalized calendar year (not -1900)
 42.1275 +     * @return the CalendarSystem to use for the specified date
 42.1276 +     */
 42.1277 +    private static final BaseCalendar getCalendarSystem(int year) {
 42.1278 +        if (year >= 1582) {
 42.1279 +            return gcal;
 42.1280 +        }
 42.1281 +        return getJulianCalendar();
 42.1282 +    }
 42.1283 +
 42.1284 +    private static final BaseCalendar getCalendarSystem(long utc) {
 42.1285 +        // Quickly check if the time stamp given by `utc' is the Epoch
 42.1286 +        // or later. If it's before 1970, we convert the cutover to
 42.1287 +        // local time to compare.
 42.1288 +        if (utc >= 0
 42.1289 +            || utc >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER
 42.1290 +                        - TimeZone.getDefaultRef().getOffset(utc)) {
 42.1291 +            return gcal;
 42.1292 +        }
 42.1293 +        return getJulianCalendar();
 42.1294 +    }
 42.1295 +
 42.1296 +    private static final BaseCalendar getCalendarSystem(BaseCalendar.Date cdate) {
 42.1297 +        if (jcal == null) {
 42.1298 +            return gcal;
 42.1299 +        }
 42.1300 +        if (cdate.getEra() != null) {
 42.1301 +            return jcal;
 42.1302 +        }
 42.1303 +        return gcal;
 42.1304 +    }
 42.1305 +
 42.1306 +    synchronized private static final BaseCalendar getJulianCalendar() {
 42.1307 +        if (jcal == null) {
 42.1308 +            jcal = (BaseCalendar) CalendarSystem.forName("julian");
 42.1309 +        }
 42.1310 +        return jcal;
 42.1311 +    }
 42.1312 +
 42.1313 +    /**
 42.1314 +     * Save the state of this object to a stream (i.e., serialize it).
 42.1315 +     *
 42.1316 +     * @serialData The value returned by <code>getTime()</code>
 42.1317 +     *             is emitted (long).  This represents the offset from
 42.1318 +     *             January 1, 1970, 00:00:00 GMT in milliseconds.
 42.1319 +     */
 42.1320 +    private void writeObject(ObjectOutputStream s)
 42.1321 +         throws IOException
 42.1322 +    {
 42.1323 +        s.writeLong(getTimeImpl());
 42.1324 +    }
 42.1325 +
 42.1326 +    /**
 42.1327 +     * Reconstitute this object from a stream (i.e., deserialize it).
 42.1328 +     */
 42.1329 +    private void readObject(ObjectInputStream s)
 42.1330 +         throws IOException, ClassNotFoundException
 42.1331 +    {
 42.1332 +        fastTime = s.readLong();
 42.1333 +    }
 42.1334 +}
    43.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    43.2 +++ b/rt/emul/compact/src/main/java/java/util/MissingResourceException.java	Thu Oct 03 15:40:35 2013 +0200
    43.3 @@ -0,0 +1,124 @@
    43.4 +/*
    43.5 + * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
    43.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    43.7 + *
    43.8 + * This code is free software; you can redistribute it and/or modify it
    43.9 + * under the terms of the GNU General Public License version 2 only, as
   43.10 + * published by the Free Software Foundation.  Oracle designates this
   43.11 + * particular file as subject to the "Classpath" exception as provided
   43.12 + * by Oracle in the LICENSE file that accompanied this code.
   43.13 + *
   43.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   43.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   43.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   43.17 + * version 2 for more details (a copy is included in the LICENSE file that
   43.18 + * accompanied this code).
   43.19 + *
   43.20 + * You should have received a copy of the GNU General Public License version
   43.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   43.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   43.23 + *
   43.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   43.25 + * or visit www.oracle.com if you need additional information or have any
   43.26 + * questions.
   43.27 + */
   43.28 +
   43.29 +/*
   43.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   43.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   43.32 + *
   43.33 + * The original version of this source code and documentation
   43.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
   43.35 + * subsidiary of IBM. These materials are provided under terms
   43.36 + * of a License Agreement between Taligent and Sun. This technology
   43.37 + * is protected by multiple US and International patents.
   43.38 + *
   43.39 + * This notice and attribution to Taligent may not be removed.
   43.40 + * Taligent is a registered trademark of Taligent, Inc.
   43.41 + *
   43.42 + */
   43.43 +
   43.44 +package java.util;
   43.45 +
   43.46 +/**
   43.47 + * Signals that a resource is missing.
   43.48 + * @see java.lang.Exception
   43.49 + * @see ResourceBundle
   43.50 + * @author      Mark Davis
   43.51 + * @since       JDK1.1
   43.52 + */
   43.53 +public
   43.54 +class MissingResourceException extends RuntimeException {
   43.55 +
   43.56 +    /**
   43.57 +     * Constructs a MissingResourceException with the specified information.
   43.58 +     * A detail message is a String that describes this particular exception.
   43.59 +     * @param s the detail message
   43.60 +     * @param className the name of the resource class
   43.61 +     * @param key the key for the missing resource.
   43.62 +     */
   43.63 +    public MissingResourceException(String s, String className, String key) {
   43.64 +        super(s);
   43.65 +        this.className = className;
   43.66 +        this.key = key;
   43.67 +    }
   43.68 +
   43.69 +    /**
   43.70 +     * Constructs a <code>MissingResourceException</code> with
   43.71 +     * <code>message</code>, <code>className</code>, <code>key</code>,
   43.72 +     * and <code>cause</code>. This constructor is package private for
   43.73 +     * use by <code>ResourceBundle.getBundle</code>.
   43.74 +     *
   43.75 +     * @param message
   43.76 +     *        the detail message
   43.77 +     * @param className
   43.78 +     *        the name of the resource class
   43.79 +     * @param key
   43.80 +     *        the key for the missing resource.
   43.81 +     * @param cause
   43.82 +     *        the cause (which is saved for later retrieval by the
   43.83 +     *        {@link Throwable.getCause()} method). (A null value is
   43.84 +     *        permitted, and indicates that the cause is nonexistent
   43.85 +     *        or unknown.)
   43.86 +     */
   43.87 +    MissingResourceException(String message, String className, String key, Throwable cause) {
   43.88 +        super(message, cause);
   43.89 +        this.className = className;
   43.90 +        this.key = key;
   43.91 +    }
   43.92 +
   43.93 +    /**
   43.94 +     * Gets parameter passed by constructor.
   43.95 +     *
   43.96 +     * @return the name of the resource class
   43.97 +     */
   43.98 +    public String getClassName() {
   43.99 +        return className;
  43.100 +    }
  43.101 +
  43.102 +    /**
  43.103 +     * Gets parameter passed by constructor.
  43.104 +     *
  43.105 +     * @return the key for the missing resource
  43.106 +     */
  43.107 +    public String getKey() {
  43.108 +        return key;
  43.109 +    }
  43.110 +
  43.111 +    //============ privates ============
  43.112 +
  43.113 +    // serialization compatibility with JDK1.1
  43.114 +    private static final long serialVersionUID = -4876345176062000401L;
  43.115 +
  43.116 +    /**
  43.117 +     * The class name of the resource bundle requested by the user.
  43.118 +     * @serial
  43.119 +     */
  43.120 +    private String className;
  43.121 +
  43.122 +    /**
  43.123 +     * The name of the specific resource requested by the user.
  43.124 +     * @serial
  43.125 +     */
  43.126 +    private String key;
  43.127 +}
    44.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    44.2 +++ b/rt/emul/compact/src/main/java/java/util/Properties.java	Thu Oct 03 15:40:35 2013 +0200
    44.3 @@ -0,0 +1,1114 @@
    44.4 +/*
    44.5 + * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
    44.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    44.7 + *
    44.8 + * This code is free software; you can redistribute it and/or modify it
    44.9 + * under the terms of the GNU General Public License version 2 only, as
   44.10 + * published by the Free Software Foundation.  Oracle designates this
   44.11 + * particular file as subject to the "Classpath" exception as provided
   44.12 + * by Oracle in the LICENSE file that accompanied this code.
   44.13 + *
   44.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   44.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   44.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   44.17 + * version 2 for more details (a copy is included in the LICENSE file that
   44.18 + * accompanied this code).
   44.19 + *
   44.20 + * You should have received a copy of the GNU General Public License version
   44.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   44.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   44.23 + *
   44.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   44.25 + * or visit www.oracle.com if you need additional information or have any
   44.26 + * questions.
   44.27 + */
   44.28 +
   44.29 +package java.util;
   44.30 +
   44.31 +import java.io.IOException;
   44.32 +import java.io.PrintStream;
   44.33 +import java.io.PrintWriter;
   44.34 +import java.io.InputStream;
   44.35 +import java.io.OutputStream;
   44.36 +import java.io.Reader;
   44.37 +import java.io.Writer;
   44.38 +import java.io.OutputStreamWriter;
   44.39 +import java.io.BufferedWriter;
   44.40 +
   44.41 +/**
   44.42 + * The <code>Properties</code> class represents a persistent set of
   44.43 + * properties. The <code>Properties</code> can be saved to a stream
   44.44 + * or loaded from a stream. Each key and its corresponding value in
   44.45 + * the property list is a string.
   44.46 + * <p>
   44.47 + * A property list can contain another property list as its
   44.48 + * "defaults"; this second property list is searched if
   44.49 + * the property key is not found in the original property list.
   44.50 + * <p>
   44.51 + * Because <code>Properties</code> inherits from <code>Hashtable</code>, the
   44.52 + * <code>put</code> and <code>putAll</code> methods can be applied to a
   44.53 + * <code>Properties</code> object.  Their use is strongly discouraged as they
   44.54 + * allow the caller to insert entries whose keys or values are not
   44.55 + * <code>Strings</code>.  The <code>setProperty</code> method should be used
   44.56 + * instead.  If the <code>store</code> or <code>save</code> method is called
   44.57 + * on a "compromised" <code>Properties</code> object that contains a
   44.58 + * non-<code>String</code> key or value, the call will fail. Similarly,
   44.59 + * the call to the <code>propertyNames</code> or <code>list</code> method
   44.60 + * will fail if it is called on a "compromised" <code>Properties</code>
   44.61 + * object that contains a non-<code>String</code> key.
   44.62 + *
   44.63 + * <p>
   44.64 + * The {@link #load(java.io.Reader) load(Reader)} <tt>/</tt>
   44.65 + * {@link #store(java.io.Writer, java.lang.String) store(Writer, String)}
   44.66 + * methods load and store properties from and to a character based stream
   44.67 + * in a simple line-oriented format specified below.
   44.68 + *
   44.69 + * The {@link #load(java.io.InputStream) load(InputStream)} <tt>/</tt>
   44.70 + * {@link #store(java.io.OutputStream, java.lang.String) store(OutputStream, String)}
   44.71 + * methods work the same way as the load(Reader)/store(Writer, String) pair, except
   44.72 + * the input/output stream is encoded in ISO 8859-1 character encoding.
   44.73 + * Characters that cannot be directly represented in this encoding can be written using
   44.74 + * Unicode escapes as defined in section 3.3 of
   44.75 + * <cite>The Java&trade; Language Specification</cite>;
   44.76 + * only a single 'u' character is allowed in an escape
   44.77 + * sequence. The native2ascii tool can be used to convert property files to and
   44.78 + * from other character encodings.
   44.79 + *
   44.80 + * <p> The {@link #loadFromXML(InputStream)} and {@link
   44.81 + * #storeToXML(OutputStream, String, String)} methods load and store properties
   44.82 + * in a simple XML format.  By default the UTF-8 character encoding is used,
   44.83 + * however a specific encoding may be specified if required.  An XML properties
   44.84 + * document has the following DOCTYPE declaration:
   44.85 + *
   44.86 + * <pre>
   44.87 + * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
   44.88 + * </pre>
   44.89 + * Note that the system URI (http://java.sun.com/dtd/properties.dtd) is
   44.90 + * <i>not</i> accessed when exporting or importing properties; it merely
   44.91 + * serves as a string to uniquely identify the DTD, which is:
   44.92 + * <pre>
   44.93 + *    &lt;?xml version="1.0" encoding="UTF-8"?&gt;
   44.94 + *
   44.95 + *    &lt;!-- DTD for properties --&gt;
   44.96 + *
   44.97 + *    &lt;!ELEMENT properties ( comment?, entry* ) &gt;
   44.98 + *
   44.99 + *    &lt;!ATTLIST properties version CDATA #FIXED "1.0"&gt;
  44.100 + *
  44.101 + *    &lt;!ELEMENT comment (#PCDATA) &gt;
  44.102 + *
  44.103 + *    &lt;!ELEMENT entry (#PCDATA) &gt;
  44.104 + *
  44.105 + *    &lt;!ATTLIST entry key CDATA #REQUIRED&gt;
  44.106 + * </pre>
  44.107 + *
  44.108 + * <p>This class is thread-safe: multiple threads can share a single
  44.109 + * <tt>Properties</tt> object without the need for external synchronization.
  44.110 + *
  44.111 + * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
  44.112 + * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
  44.113 + *
  44.114 + * @author  Arthur van Hoff
  44.115 + * @author  Michael McCloskey
  44.116 + * @author  Xueming Shen
  44.117 + * @since   JDK1.0
  44.118 + */
  44.119 +public
  44.120 +class Properties extends Hashtable<Object,Object> {
  44.121 +    /**
  44.122 +     * use serialVersionUID from JDK 1.1.X for interoperability
  44.123 +     */
  44.124 +     private static final long serialVersionUID = 4112578634029874840L;
  44.125 +
  44.126 +    /**
  44.127 +     * A property list that contains default values for any keys not
  44.128 +     * found in this property list.
  44.129 +     *
  44.130 +     * @serial
  44.131 +     */
  44.132 +    protected Properties defaults;
  44.133 +
  44.134 +    /**
  44.135 +     * Creates an empty property list with no default values.
  44.136 +     */
  44.137 +    public Properties() {
  44.138 +        this(null);
  44.139 +    }
  44.140 +
  44.141 +    /**
  44.142 +     * Creates an empty property list with the specified defaults.
  44.143 +     *
  44.144 +     * @param   defaults   the defaults.
  44.145 +     */
  44.146 +    public Properties(Properties defaults) {
  44.147 +        this.defaults = defaults;
  44.148 +    }
  44.149 +
  44.150 +    /**
  44.151 +     * Calls the <tt>Hashtable</tt> method <code>put</code>. Provided for
  44.152 +     * parallelism with the <tt>getProperty</tt> method. Enforces use of
  44.153 +     * strings for property keys and values. The value returned is the
  44.154 +     * result of the <tt>Hashtable</tt> call to <code>put</code>.
  44.155 +     *
  44.156 +     * @param key the key to be placed into this property list.
  44.157 +     * @param value the value corresponding to <tt>key</tt>.
  44.158 +     * @return     the previous value of the specified key in this property
  44.159 +     *             list, or <code>null</code> if it did not have one.
  44.160 +     * @see #getProperty
  44.161 +     * @since    1.2
  44.162 +     */
  44.163 +    public synchronized Object setProperty(String key, String value) {
  44.164 +        return put(key, value);
  44.165 +    }
  44.166 +
  44.167 +
  44.168 +    /**
  44.169 +     * Reads a property list (key and element pairs) from the input
  44.170 +     * character stream in a simple line-oriented format.
  44.171 +     * <p>
  44.172 +     * Properties are processed in terms of lines. There are two
  44.173 +     * kinds of line, <i>natural lines</i> and <i>logical lines</i>.
  44.174 +     * A natural line is defined as a line of
  44.175 +     * characters that is terminated either by a set of line terminator
  44.176 +     * characters (<code>\n</code> or <code>\r</code> or <code>\r\n</code>)
  44.177 +     * or by the end of the stream. A natural line may be either a blank line,
  44.178 +     * a comment line, or hold all or some of a key-element pair. A logical
  44.179 +     * line holds all the data of a key-element pair, which may be spread
  44.180 +     * out across several adjacent natural lines by escaping
  44.181 +     * the line terminator sequence with a backslash character
  44.182 +     * <code>\</code>.  Note that a comment line cannot be extended
  44.183 +     * in this manner; every natural line that is a comment must have
  44.184 +     * its own comment indicator, as described below. Lines are read from
  44.185 +     * input until the end of the stream is reached.
  44.186 +     *
  44.187 +     * <p>
  44.188 +     * A natural line that contains only white space characters is
  44.189 +     * considered blank and is ignored.  A comment line has an ASCII
  44.190 +     * <code>'#'</code> or <code>'!'</code> as its first non-white
  44.191 +     * space character; comment lines are also ignored and do not
  44.192 +     * encode key-element information.  In addition to line
  44.193 +     * terminators, this format considers the characters space
  44.194 +     * (<code>' '</code>, <code>'&#92;u0020'</code>), tab
  44.195 +     * (<code>'\t'</code>, <code>'&#92;u0009'</code>), and form feed
  44.196 +     * (<code>'\f'</code>, <code>'&#92;u000C'</code>) to be white
  44.197 +     * space.
  44.198 +     *
  44.199 +     * <p>
  44.200 +     * If a logical line is spread across several natural lines, the
  44.201 +     * backslash escaping the line terminator sequence, the line
  44.202 +     * terminator sequence, and any white space at the start of the
  44.203 +     * following line have no affect on the key or element values.
  44.204 +     * The remainder of the discussion of key and element parsing
  44.205 +     * (when loading) will assume all the characters constituting
  44.206 +     * the key and element appear on a single natural line after
  44.207 +     * line continuation characters have been removed.  Note that
  44.208 +     * it is <i>not</i> sufficient to only examine the character
  44.209 +     * preceding a line terminator sequence to decide if the line
  44.210 +     * terminator is escaped; there must be an odd number of
  44.211 +     * contiguous backslashes for the line terminator to be escaped.
  44.212 +     * Since the input is processed from left to right, a
  44.213 +     * non-zero even number of 2<i>n</i> contiguous backslashes
  44.214 +     * before a line terminator (or elsewhere) encodes <i>n</i>
  44.215 +     * backslashes after escape processing.
  44.216 +     *
  44.217 +     * <p>
  44.218 +     * The key contains all of the characters in the line starting
  44.219 +     * with the first non-white space character and up to, but not
  44.220 +     * including, the first unescaped <code>'='</code>,
  44.221 +     * <code>':'</code>, or white space character other than a line
  44.222 +     * terminator. All of these key termination characters may be
  44.223 +     * included in the key by escaping them with a preceding backslash
  44.224 +     * character; for example,<p>
  44.225 +     *
  44.226 +     * <code>\:\=</code><p>
  44.227 +     *
  44.228 +     * would be the two-character key <code>":="</code>.  Line
  44.229 +     * terminator characters can be included using <code>\r</code> and
  44.230 +     * <code>\n</code> escape sequences.  Any white space after the
  44.231 +     * key is skipped; if the first non-white space character after
  44.232 +     * the key is <code>'='</code> or <code>':'</code>, then it is
  44.233 +     * ignored and any white space characters after it are also
  44.234 +     * skipped.  All remaining characters on the line become part of
  44.235 +     * the associated element string; if there are no remaining
  44.236 +     * characters, the element is the empty string
  44.237 +     * <code>&quot;&quot;</code>.  Once the raw character sequences
  44.238 +     * constituting the key and element are identified, escape
  44.239 +     * processing is performed as described above.
  44.240 +     *
  44.241 +     * <p>
  44.242 +     * As an example, each of the following three lines specifies the key
  44.243 +     * <code>"Truth"</code> and the associated element value
  44.244 +     * <code>"Beauty"</code>:
  44.245 +     * <p>
  44.246 +     * <pre>
  44.247 +     * Truth = Beauty
  44.248 +     *  Truth:Beauty
  44.249 +     * Truth                    :Beauty
  44.250 +     * </pre>
  44.251 +     * As another example, the following three lines specify a single
  44.252 +     * property:
  44.253 +     * <p>
  44.254 +     * <pre>
  44.255 +     * fruits                           apple, banana, pear, \
  44.256 +     *                                  cantaloupe, watermelon, \
  44.257 +     *                                  kiwi, mango
  44.258 +     * </pre>
  44.259 +     * The key is <code>"fruits"</code> and the associated element is:
  44.260 +     * <p>
  44.261 +     * <pre>"apple, banana, pear, cantaloupe, watermelon, kiwi, mango"</pre>
  44.262 +     * Note that a space appears before each <code>\</code> so that a space
  44.263 +     * will appear after each comma in the final result; the <code>\</code>,
  44.264 +     * line terminator, and leading white space on the continuation line are
  44.265 +     * merely discarded and are <i>not</i> replaced by one or more other
  44.266 +     * characters.
  44.267 +     * <p>
  44.268 +     * As a third example, the line:
  44.269 +     * <p>
  44.270 +     * <pre>cheeses
  44.271 +     * </pre>
  44.272 +     * specifies that the key is <code>"cheeses"</code> and the associated
  44.273 +     * element is the empty string <code>""</code>.<p>
  44.274 +     * <p>
  44.275 +     *
  44.276 +     * <a name="unicodeescapes"></a>
  44.277 +     * Characters in keys and elements can be represented in escape
  44.278 +     * sequences similar to those used for character and string literals
  44.279 +     * (see sections 3.3 and 3.10.6 of
  44.280 +     * <cite>The Java&trade; Language Specification</cite>).
  44.281 +     *
  44.282 +     * The differences from the character escape sequences and Unicode
  44.283 +     * escapes used for characters and strings are:
  44.284 +     *
  44.285 +     * <ul>
  44.286 +     * <li> Octal escapes are not recognized.
  44.287 +     *
  44.288 +     * <li> The character sequence <code>\b</code> does <i>not</i>
  44.289 +     * represent a backspace character.
  44.290 +     *
  44.291 +     * <li> The method does not treat a backslash character,
  44.292 +     * <code>\</code>, before a non-valid escape character as an
  44.293 +     * error; the backslash is silently dropped.  For example, in a
  44.294 +     * Java string the sequence <code>"\z"</code> would cause a
  44.295 +     * compile time error.  In contrast, this method silently drops
  44.296 +     * the backslash.  Therefore, this method treats the two character
  44.297 +     * sequence <code>"\b"</code> as equivalent to the single
  44.298 +     * character <code>'b'</code>.
  44.299 +     *
  44.300 +     * <li> Escapes are not necessary for single and double quotes;
  44.301 +     * however, by the rule above, single and double quote characters
  44.302 +     * preceded by a backslash still yield single and double quote
  44.303 +     * characters, respectively.
  44.304 +     *
  44.305 +     * <li> Only a single 'u' character is allowed in a Uniocde escape
  44.306 +     * sequence.
  44.307 +     *
  44.308 +     * </ul>
  44.309 +     * <p>
  44.310 +     * The specified stream remains open after this method returns.
  44.311 +     *
  44.312 +     * @param   reader   the input character stream.
  44.313 +     * @throws  IOException  if an error occurred when reading from the
  44.314 +     *          input stream.
  44.315 +     * @throws  IllegalArgumentException if a malformed Unicode escape
  44.316 +     *          appears in the input.
  44.317 +     * @since   1.6
  44.318 +     */
  44.319 +    public synchronized void load(Reader reader) throws IOException {
  44.320 +        load0(new LineReader(reader));
  44.321 +    }
  44.322 +
  44.323 +    /**
  44.324 +     * Reads a property list (key and element pairs) from the input
  44.325 +     * byte stream. The input stream is in a simple line-oriented
  44.326 +     * format as specified in
  44.327 +     * {@link #load(java.io.Reader) load(Reader)} and is assumed to use
  44.328 +     * the ISO 8859-1 character encoding; that is each byte is one Latin1
  44.329 +     * character. Characters not in Latin1, and certain special characters,
  44.330 +     * are represented in keys and elements using Unicode escapes as defined in
  44.331 +     * section 3.3 of
  44.332 +     * <cite>The Java&trade; Language Specification</cite>.
  44.333 +     * <p>
  44.334 +     * The specified stream remains open after this method returns.
  44.335 +     *
  44.336 +     * @param      inStream   the input stream.
  44.337 +     * @exception  IOException  if an error occurred when reading from the
  44.338 +     *             input stream.
  44.339 +     * @throws     IllegalArgumentException if the input stream contains a
  44.340 +     *             malformed Unicode escape sequence.
  44.341 +     * @since 1.2
  44.342 +     */
  44.343 +    public synchronized void load(InputStream inStream) throws IOException {
  44.344 +        load0(new LineReader(inStream));
  44.345 +    }
  44.346 +
  44.347 +    private void load0 (LineReader lr) throws IOException {
  44.348 +        char[] convtBuf = new char[1024];
  44.349 +        int limit;
  44.350 +        int keyLen;
  44.351 +        int valueStart;
  44.352 +        char c;
  44.353 +        boolean hasSep;
  44.354 +        boolean precedingBackslash;
  44.355 +
  44.356 +        while ((limit = lr.readLine()) >= 0) {
  44.357 +            c = 0;
  44.358 +            keyLen = 0;
  44.359 +            valueStart = limit;
  44.360 +            hasSep = false;
  44.361 +
  44.362 +            //System.out.println("line=<" + new String(lineBuf, 0, limit) + ">");
  44.363 +            precedingBackslash = false;
  44.364 +            while (keyLen < limit) {
  44.365 +                c = lr.lineBuf[keyLen];
  44.366 +                //need check if escaped.
  44.367 +                if ((c == '=' ||  c == ':') && !precedingBackslash) {
  44.368 +                    valueStart = keyLen + 1;
  44.369 +                    hasSep = true;
  44.370 +                    break;
  44.371 +                } else if ((c == ' ' || c == '\t' ||  c == '\f') && !precedingBackslash) {
  44.372 +                    valueStart = keyLen + 1;
  44.373 +                    break;
  44.374 +                }
  44.375 +                if (c == '\\') {
  44.376 +                    precedingBackslash = !precedingBackslash;
  44.377 +                } else {
  44.378 +                    precedingBackslash = false;
  44.379 +                }
  44.380 +                keyLen++;
  44.381 +            }
  44.382 +            while (valueStart < limit) {
  44.383 +                c = lr.lineBuf[valueStart];
  44.384 +                if (c != ' ' && c != '\t' &&  c != '\f') {
  44.385 +                    if (!hasSep && (c == '=' ||  c == ':')) {
  44.386 +                        hasSep = true;
  44.387 +                    } else {
  44.388 +                        break;
  44.389 +                    }
  44.390 +                }
  44.391 +                valueStart++;
  44.392 +            }
  44.393 +            String key = loadConvert(lr.lineBuf, 0, keyLen, convtBuf);
  44.394 +            String value = loadConvert(lr.lineBuf, valueStart, limit - valueStart, convtBuf);
  44.395 +            put(key, value);
  44.396 +        }
  44.397 +    }
  44.398 +
  44.399 +    /* Read in a "logical line" from an InputStream/Reader, skip all comment
  44.400 +     * and blank lines and filter out those leading whitespace characters
  44.401 +     * (\u0020, \u0009 and \u000c) from the beginning of a "natural line".
  44.402 +     * Method returns the char length of the "logical line" and stores
  44.403 +     * the line in "lineBuf".
  44.404 +     */
  44.405 +    class LineReader {
  44.406 +        public LineReader(InputStream inStream) {
  44.407 +            this.inStream = inStream;
  44.408 +            inByteBuf = new byte[8192];
  44.409 +        }
  44.410 +
  44.411 +        public LineReader(Reader reader) {
  44.412 +            this.reader = reader;
  44.413 +            inCharBuf = new char[8192];
  44.414 +        }
  44.415 +
  44.416 +        byte[] inByteBuf;
  44.417 +        char[] inCharBuf;
  44.418 +        char[] lineBuf = new char[1024];
  44.419 +        int inLimit = 0;
  44.420 +        int inOff = 0;
  44.421 +        InputStream inStream;
  44.422 +        Reader reader;
  44.423 +
  44.424 +        int readLine() throws IOException {
  44.425 +            int len = 0;
  44.426 +            char c = 0;
  44.427 +
  44.428 +            boolean skipWhiteSpace = true;
  44.429 +            boolean isCommentLine = false;
  44.430 +            boolean isNewLine = true;
  44.431 +            boolean appendedLineBegin = false;
  44.432 +            boolean precedingBackslash = false;
  44.433 +            boolean skipLF = false;
  44.434 +
  44.435 +            while (true) {
  44.436 +                if (inOff >= inLimit) {
  44.437 +                    inLimit = (inStream==null)?reader.read(inCharBuf)
  44.438 +                                              :inStream.read(inByteBuf);
  44.439 +                    inOff = 0;
  44.440 +                    if (inLimit <= 0) {
  44.441 +                        if (len == 0 || isCommentLine) {
  44.442 +                            return -1;
  44.443 +                        }
  44.444 +                        return len;
  44.445 +                    }
  44.446 +                }
  44.447 +                if (inStream != null) {
  44.448 +                    //The line below is equivalent to calling a
  44.449 +                    //ISO8859-1 decoder.
  44.450 +                    c = (char) (0xff & inByteBuf[inOff++]);
  44.451 +                } else {
  44.452 +                    c = inCharBuf[inOff++];
  44.453 +                }
  44.454 +                if (skipLF) {
  44.455 +                    skipLF = false;
  44.456 +                    if (c == '\n') {
  44.457 +                        continue;
  44.458 +                    }
  44.459 +                }
  44.460 +                if (skipWhiteSpace) {
  44.461 +                    if (c == ' ' || c == '\t' || c == '\f') {
  44.462 +                        continue;
  44.463 +                    }
  44.464 +                    if (!appendedLineBegin && (c == '\r' || c == '\n')) {
  44.465 +                        continue;
  44.466 +                    }
  44.467 +                    skipWhiteSpace = false;
  44.468 +                    appendedLineBegin = false;
  44.469 +                }
  44.470 +                if (isNewLine) {
  44.471 +                    isNewLine = false;
  44.472 +                    if (c == '#' || c == '!') {
  44.473 +                        isCommentLine = true;
  44.474 +                        continue;
  44.475 +                    }
  44.476 +                }
  44.477 +
  44.478 +                if (c != '\n' && c != '\r') {
  44.479 +                    lineBuf[len++] = c;
  44.480 +                    if (len == lineBuf.length) {
  44.481 +                        int newLength = lineBuf.length * 2;
  44.482 +                        if (newLength < 0) {
  44.483 +                            newLength = Integer.MAX_VALUE;
  44.484 +                        }
  44.485 +                        char[] buf = new char[newLength];
  44.486 +                        System.arraycopy(lineBuf, 0, buf, 0, lineBuf.length);
  44.487 +                        lineBuf = buf;
  44.488 +                    }
  44.489 +                    //flip the preceding backslash flag
  44.490 +                    if (c == '\\') {
  44.491 +                        precedingBackslash = !precedingBackslash;
  44.492 +                    } else {
  44.493 +                        precedingBackslash = false;
  44.494 +                    }
  44.495 +                }
  44.496 +                else {
  44.497 +                    // reached EOL
  44.498 +                    if (isCommentLine || len == 0) {
  44.499 +                        isCommentLine = false;
  44.500 +                        isNewLine = true;
  44.501 +                        skipWhiteSpace = true;
  44.502 +                        len = 0;
  44.503 +                        continue;
  44.504 +                    }
  44.505 +                    if (inOff >= inLimit) {
  44.506 +                        inLimit = (inStream==null)
  44.507 +                                  ?reader.read(inCharBuf)
  44.508 +                                  :inStream.read(inByteBuf);
  44.509 +                        inOff = 0;
  44.510 +                        if (inLimit <= 0) {
  44.511 +                            return len;
  44.512 +                        }
  44.513 +                    }
  44.514 +                    if (precedingBackslash) {
  44.515 +                        len -= 1;
  44.516 +                        //skip the leading whitespace characters in following line
  44.517 +                        skipWhiteSpace = true;
  44.518 +                        appendedLineBegin = true;
  44.519 +                        precedingBackslash = false;
  44.520 +                        if (c == '\r') {
  44.521 +                            skipLF = true;
  44.522 +                        }
  44.523 +                    } else {
  44.524 +                        return len;
  44.525 +                    }
  44.526 +                }
  44.527 +            }
  44.528 +        }
  44.529 +    }
  44.530 +
  44.531 +    /*
  44.532 +     * Converts encoded &#92;uxxxx to unicode chars
  44.533 +     * and changes special saved chars to their original forms
  44.534 +     */
  44.535 +    private String loadConvert (char[] in, int off, int len, char[] convtBuf) {
  44.536 +        if (convtBuf.length < len) {
  44.537 +            int newLen = len * 2;
  44.538 +            if (newLen < 0) {
  44.539 +                newLen = Integer.MAX_VALUE;
  44.540 +            }
  44.541 +            convtBuf = new char[newLen];
  44.542 +        }
  44.543 +        char aChar;
  44.544 +        char[] out = convtBuf;
  44.545 +        int outLen = 0;
  44.546 +        int end = off + len;
  44.547 +
  44.548 +        while (off < end) {
  44.549 +            aChar = in[off++];
  44.550 +            if (aChar == '\\') {
  44.551 +                aChar = in[off++];
  44.552 +                if(aChar == 'u') {
  44.553 +                    // Read the xxxx
  44.554 +                    int value=0;
  44.555 +                    for (int i=0; i<4; i++) {
  44.556 +                        aChar = in[off++];
  44.557 +                        switch (aChar) {
  44.558 +                          case '0': case '1': case '2': case '3': case '4':
  44.559 +                          case '5': case '6': case '7': case '8': case '9':
  44.560 +                             value = (value << 4) + aChar - '0';
  44.561 +                             break;
  44.562 +                          case 'a': case 'b': case 'c':
  44.563 +                          case 'd': case 'e': case 'f':
  44.564 +                             value = (value << 4) + 10 + aChar - 'a';
  44.565 +                             break;
  44.566 +                          case 'A': case 'B': case 'C':
  44.567 +                          case 'D': case 'E': case 'F':
  44.568 +                             value = (value << 4) + 10 + aChar - 'A';
  44.569 +                             break;
  44.570 +                          default:
  44.571 +                              throw new IllegalArgumentException(
  44.572 +                                           "Malformed \\uxxxx encoding.");
  44.573 +                        }
  44.574 +                     }
  44.575 +                    out[outLen++] = (char)value;
  44.576 +                } else {
  44.577 +                    if (aChar == 't') aChar = '\t';
  44.578 +                    else if (aChar == 'r') aChar = '\r';
  44.579 +                    else if (aChar == 'n') aChar = '\n';
  44.580 +                    else if (aChar == 'f') aChar = '\f';
  44.581 +                    out[outLen++] = aChar;
  44.582 +                }
  44.583 +            } else {
  44.584 +                out[outLen++] = aChar;
  44.585 +            }
  44.586 +        }
  44.587 +        return new String (out, 0, outLen);
  44.588 +    }
  44.589 +
  44.590 +    /*
  44.591 +     * Converts unicodes to encoded &#92;uxxxx and escapes
  44.592 +     * special characters with a preceding slash
  44.593 +     */
  44.594 +    private String saveConvert(String theString,
  44.595 +                               boolean escapeSpace,
  44.596 +                               boolean escapeUnicode) {
  44.597 +        int len = theString.length();
  44.598 +        int bufLen = len * 2;
  44.599 +        if (bufLen < 0) {
  44.600 +            bufLen = Integer.MAX_VALUE;
  44.601 +        }
  44.602 +        StringBuffer outBuffer = new StringBuffer(bufLen);
  44.603 +
  44.604 +        for(int x=0; x<len; x++) {
  44.605 +            char aChar = theString.charAt(x);
  44.606 +            // Handle common case first, selecting largest block that
  44.607 +            // avoids the specials below
  44.608 +            if ((aChar > 61) && (aChar < 127)) {
  44.609 +                if (aChar == '\\') {
  44.610 +                    outBuffer.append('\\'); outBuffer.append('\\');
  44.611 +                    continue;
  44.612 +                }
  44.613 +                outBuffer.append(aChar);
  44.614 +                continue;
  44.615 +            }
  44.616 +            switch(aChar) {
  44.617 +                case ' ':
  44.618 +                    if (x == 0 || escapeSpace)
  44.619 +                        outBuffer.append('\\');
  44.620 +                    outBuffer.append(' ');
  44.621 +                    break;
  44.622 +                case '\t':outBuffer.append('\\'); outBuffer.append('t');
  44.623 +                          break;
  44.624 +                case '\n':outBuffer.append('\\'); outBuffer.append('n');
  44.625 +                          break;
  44.626 +                case '\r':outBuffer.append('\\'); outBuffer.append('r');
  44.627 +                          break;
  44.628 +                case '\f':outBuffer.append('\\'); outBuffer.append('f');
  44.629 +                          break;
  44.630 +                case '=': // Fall through
  44.631 +                case ':': // Fall through
  44.632 +                case '#': // Fall through
  44.633 +                case '!':
  44.634 +                    outBuffer.append('\\'); outBuffer.append(aChar);
  44.635 +                    break;
  44.636 +                default:
  44.637 +                    if (((aChar < 0x0020) || (aChar > 0x007e)) & escapeUnicode ) {
  44.638 +                        outBuffer.append('\\');
  44.639 +                        outBuffer.append('u');
  44.640 +                        outBuffer.append(toHex((aChar >> 12) & 0xF));
  44.641 +                        outBuffer.append(toHex((aChar >>  8) & 0xF));
  44.642 +                        outBuffer.append(toHex((aChar >>  4) & 0xF));
  44.643 +                        outBuffer.append(toHex( aChar        & 0xF));
  44.644 +                    } else {
  44.645 +                        outBuffer.append(aChar);
  44.646 +                    }
  44.647 +            }
  44.648 +        }
  44.649 +        return outBuffer.toString();
  44.650 +    }
  44.651 +
  44.652 +    private static void writeComments(BufferedWriter bw, String comments)
  44.653 +        throws IOException {
  44.654 +        bw.write("#");
  44.655 +        int len = comments.length();
  44.656 +        int current = 0;
  44.657 +        int last = 0;
  44.658 +        char[] uu = new char[6];
  44.659 +        uu[0] = '\\';
  44.660 +        uu[1] = 'u';
  44.661 +        while (current < len) {
  44.662 +            char c = comments.charAt(current);
  44.663 +            if (c > '\u00ff' || c == '\n' || c == '\r') {
  44.664 +                if (last != current)
  44.665 +                    bw.write(comments.substring(last, current));
  44.666 +                if (c > '\u00ff') {
  44.667 +                    uu[2] = toHex((c >> 12) & 0xf);
  44.668 +                    uu[3] = toHex((c >>  8) & 0xf);
  44.669 +                    uu[4] = toHex((c >>  4) & 0xf);
  44.670 +                    uu[5] = toHex( c        & 0xf);
  44.671 +                    bw.write(new String(uu));
  44.672 +                } else {
  44.673 +                    bw.newLine();
  44.674 +                    if (c == '\r' &&
  44.675 +                        current != len - 1 &&
  44.676 +                        comments.charAt(current + 1) == '\n') {
  44.677 +                        current++;
  44.678 +                    }
  44.679 +                    if (current == len - 1 ||
  44.680 +                        (comments.charAt(current + 1) != '#' &&
  44.681 +                        comments.charAt(current + 1) != '!'))
  44.682 +                        bw.write("#");
  44.683 +                }
  44.684 +                last = current + 1;
  44.685 +            }
  44.686 +            current++;
  44.687 +        }
  44.688 +        if (last != current)
  44.689 +            bw.write(comments.substring(last, current));
  44.690 +        bw.newLine();
  44.691 +    }
  44.692 +
  44.693 +    /**
  44.694 +     * Calls the <code>store(OutputStream out, String comments)</code> method
  44.695 +     * and suppresses IOExceptions that were thrown.
  44.696 +     *
  44.697 +     * @deprecated This method does not throw an IOException if an I/O error
  44.698 +     * occurs while saving the property list.  The preferred way to save a
  44.699 +     * properties list is via the <code>store(OutputStream out,
  44.700 +     * String comments)</code> method or the
  44.701 +     * <code>storeToXML(OutputStream os, String comment)</code> method.
  44.702 +     *
  44.703 +     * @param   out      an output stream.
  44.704 +     * @param   comments   a description of the property list.
  44.705 +     * @exception  ClassCastException  if this <code>Properties</code> object
  44.706 +     *             contains any keys or values that are not
  44.707 +     *             <code>Strings</code>.
  44.708 +     */
  44.709 +    @Deprecated
  44.710 +    public void save(OutputStream out, String comments)  {
  44.711 +        try {
  44.712 +            store(out, comments);
  44.713 +        } catch (IOException e) {
  44.714 +        }
  44.715 +    }
  44.716 +
  44.717 +    /**
  44.718 +     * Writes this property list (key and element pairs) in this
  44.719 +     * <code>Properties</code> table to the output character stream in a
  44.720 +     * format suitable for using the {@link #load(java.io.Reader) load(Reader)}
  44.721 +     * method.
  44.722 +     * <p>
  44.723 +     * Properties from the defaults table of this <code>Properties</code>
  44.724 +     * table (if any) are <i>not</i> written out by this method.
  44.725 +     * <p>
  44.726 +     * If the comments argument is not null, then an ASCII <code>#</code>
  44.727 +     * character, the comments string, and a line separator are first written
  44.728 +     * to the output stream. Thus, the <code>comments</code> can serve as an
  44.729 +     * identifying comment. Any one of a line feed ('\n'), a carriage
  44.730 +     * return ('\r'), or a carriage return followed immediately by a line feed
  44.731 +     * in comments is replaced by a line separator generated by the <code>Writer</code>
  44.732 +     * and if the next character in comments is not character <code>#</code> or
  44.733 +     * character <code>!</code> then an ASCII <code>#</code> is written out
  44.734 +     * after that line separator.
  44.735 +     * <p>
  44.736 +     * Next, a comment line is always written, consisting of an ASCII
  44.737 +     * <code>#</code> character, the current date and time (as if produced
  44.738 +     * by the <code>toString</code> method of <code>Date</code> for the
  44.739 +     * current time), and a line separator as generated by the <code>Writer</code>.
  44.740 +     * <p>
  44.741 +     * Then every entry in this <code>Properties</code> table is
  44.742 +     * written out, one per line. For each entry the key string is
  44.743 +     * written, then an ASCII <code>=</code>, then the associated
  44.744 +     * element string. For the key, all space characters are
  44.745 +     * written with a preceding <code>\</code> character.  For the
  44.746 +     * element, leading space characters, but not embedded or trailing
  44.747 +     * space characters, are written with a preceding <code>\</code>
  44.748 +     * character. The key and element characters <code>#</code>,
  44.749 +     * <code>!</code>, <code>=</code>, and <code>:</code> are written
  44.750 +     * with a preceding backslash to ensure that they are properly loaded.
  44.751 +     * <p>
  44.752 +     * After the entries have been written, the output stream is flushed.
  44.753 +     * The output stream remains open after this method returns.
  44.754 +     * <p>
  44.755 +     *
  44.756 +     * @param   writer      an output character stream writer.
  44.757 +     * @param   comments   a description of the property list.
  44.758 +     * @exception  IOException if writing this property list to the specified
  44.759 +     *             output stream throws an <tt>IOException</tt>.
  44.760 +     * @exception  ClassCastException  if this <code>Properties</code> object
  44.761 +     *             contains any keys or values that are not <code>Strings</code>.
  44.762 +     * @exception  NullPointerException  if <code>writer</code> is null.
  44.763 +     * @since 1.6
  44.764 +     */
  44.765 +    public void store(Writer writer, String comments)
  44.766 +        throws IOException
  44.767 +    {
  44.768 +        store0((writer instanceof BufferedWriter)?(BufferedWriter)writer
  44.769 +                                                 : new BufferedWriter(writer),
  44.770 +               comments,
  44.771 +               false);
  44.772 +    }
  44.773 +
  44.774 +    /**
  44.775 +     * Writes this property list (key and element pairs) in this
  44.776 +     * <code>Properties</code> table to the output stream in a format suitable
  44.777 +     * for loading into a <code>Properties</code> table using the
  44.778 +     * {@link #load(InputStream) load(InputStream)} method.
  44.779 +     * <p>
  44.780 +     * Properties from the defaults table of this <code>Properties</code>
  44.781 +     * table (if any) are <i>not</i> written out by this method.
  44.782 +     * <p>
  44.783 +     * This method outputs the comments, properties keys and values in
  44.784 +     * the same format as specified in
  44.785 +     * {@link #store(java.io.Writer, java.lang.String) store(Writer)},
  44.786 +     * with the following differences:
  44.787 +     * <ul>
  44.788 +     * <li>The stream is written using the ISO 8859-1 character encoding.
  44.789 +     *
  44.790 +     * <li>Characters not in Latin-1 in the comments are written as
  44.791 +     * <code>&#92;u</code><i>xxxx</i> for their appropriate unicode
  44.792 +     * hexadecimal value <i>xxxx</i>.
  44.793 +     *
  44.794 +     * <li>Characters less than <code>&#92;u0020</code> and characters greater
  44.795 +     * than <code>&#92;u007E</code> in property keys or values are written
  44.796 +     * as <code>&#92;u</code><i>xxxx</i> for the appropriate hexadecimal
  44.797 +     * value <i>xxxx</i>.
  44.798 +     * </ul>
  44.799 +     * <p>
  44.800 +     * After the entries have been written, the output stream is flushed.
  44.801 +     * The output stream remains open after this method returns.
  44.802 +     * <p>
  44.803 +     * @param   out      an output stream.
  44.804 +     * @param   comments   a description of the property list.
  44.805 +     * @exception  IOException if writing this property list to the specified
  44.806 +     *             output stream throws an <tt>IOException</tt>.
  44.807 +     * @exception  ClassCastException  if this <code>Properties</code> object
  44.808 +     *             contains any keys or values that are not <code>Strings</code>.
  44.809 +     * @exception  NullPointerException  if <code>out</code> is null.
  44.810 +     * @since 1.2
  44.811 +     */
  44.812 +    public void store(OutputStream out, String comments)
  44.813 +        throws IOException
  44.814 +    {
  44.815 +        store0(new BufferedWriter(new OutputStreamWriter(out, "8859_1")),
  44.816 +               comments,
  44.817 +               true);
  44.818 +    }
  44.819 +
  44.820 +    private void store0(BufferedWriter bw, String comments, boolean escUnicode)
  44.821 +        throws IOException
  44.822 +    {
  44.823 +        if (comments != null) {
  44.824 +            writeComments(bw, comments);
  44.825 +        }
  44.826 +        bw.write("#" + new Date().toString());
  44.827 +        bw.newLine();
  44.828 +        synchronized (this) {
  44.829 +            for (Enumeration e = keys(); e.hasMoreElements();) {
  44.830 +                String key = (String)e.nextElement();
  44.831 +                String val = (String)get(key);
  44.832 +                key = saveConvert(key, true, escUnicode);
  44.833 +                /* No need to escape embedded and trailing spaces for value, hence
  44.834 +                 * pass false to flag.
  44.835 +                 */
  44.836 +                val = saveConvert(val, false, escUnicode);
  44.837 +                bw.write(key + "=" + val);
  44.838 +                bw.newLine();
  44.839 +            }
  44.840 +        }
  44.841 +        bw.flush();
  44.842 +    }
  44.843 +
  44.844 +    /**
  44.845 +     * Loads all of the properties represented by the XML document on the
  44.846 +     * specified input stream into this properties table.
  44.847 +     *
  44.848 +     * <p>The XML document must have the following DOCTYPE declaration:
  44.849 +     * <pre>
  44.850 +     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
  44.851 +     * </pre>
  44.852 +     * Furthermore, the document must satisfy the properties DTD described
  44.853 +     * above.
  44.854 +     *
  44.855 +     * <p>The specified stream is closed after this method returns.
  44.856 +     *
  44.857 +     * @param in the input stream from which to read the XML document.
  44.858 +     * @throws IOException if reading from the specified input stream
  44.859 +     *         results in an <tt>IOException</tt>.
  44.860 +     * @throws InvalidPropertiesFormatException Data on input stream does not
  44.861 +     *         constitute a valid XML document with the mandated document type.
  44.862 +     * @throws NullPointerException if <code>in</code> is null.
  44.863 +     * @see    #storeToXML(OutputStream, String, String)
  44.864 +     * @since 1.5
  44.865 +     */
  44.866 +    public synchronized void loadFromXML(InputStream in)
  44.867 +        throws IOException, InvalidPropertiesFormatException
  44.868 +    {
  44.869 +        if (in == null)
  44.870 +            throw new NullPointerException();
  44.871 +        XMLUtils.load(this, in);
  44.872 +        in.close();
  44.873 +    }
  44.874 +
  44.875 +    /**
  44.876 +     * Emits an XML document representing all of the properties contained
  44.877 +     * in this table.
  44.878 +     *
  44.879 +     * <p> An invocation of this method of the form <tt>props.storeToXML(os,
  44.880 +     * comment)</tt> behaves in exactly the same way as the invocation
  44.881 +     * <tt>props.storeToXML(os, comment, "UTF-8");</tt>.
  44.882 +     *
  44.883 +     * @param os the output stream on which to emit the XML document.
  44.884 +     * @param comment a description of the property list, or <code>null</code>
  44.885 +     *        if no comment is desired.
  44.886 +     * @throws IOException if writing to the specified output stream
  44.887 +     *         results in an <tt>IOException</tt>.
  44.888 +     * @throws NullPointerException if <code>os</code> is null.
  44.889 +     * @throws ClassCastException  if this <code>Properties</code> object
  44.890 +     *         contains any keys or values that are not
  44.891 +     *         <code>Strings</code>.
  44.892 +     * @see    #loadFromXML(InputStream)
  44.893 +     * @since 1.5
  44.894 +     */
  44.895 +    public void storeToXML(OutputStream os, String comment)
  44.896 +        throws IOException
  44.897 +    {
  44.898 +        if (os == null)
  44.899 +            throw new NullPointerException();
  44.900 +        storeToXML(os, comment, "UTF-8");
  44.901 +    }
  44.902 +
  44.903 +    /**
  44.904 +     * Emits an XML document representing all of the properties contained
  44.905 +     * in this table, using the specified encoding.
  44.906 +     *
  44.907 +     * <p>The XML document will have the following DOCTYPE declaration:
  44.908 +     * <pre>
  44.909 +     * &lt;!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd"&gt;
  44.910 +     * </pre>
  44.911 +     *
  44.912 +     *<p>If the specified comment is <code>null</code> then no comment
  44.913 +     * will be stored in the document.
  44.914 +     *
  44.915 +     * <p>The specified stream remains open after this method returns.
  44.916 +     *
  44.917 +     * @param os        the output stream on which to emit the XML document.
  44.918 +     * @param comment   a description of the property list, or <code>null</code>
  44.919 +     *                  if no comment is desired.
  44.920 +     * @param  encoding the name of a supported
  44.921 +     *                  <a href="../lang/package-summary.html#charenc">
  44.922 +     *                  character encoding</a>
  44.923 +     *
  44.924 +     * @throws IOException if writing to the specified output stream
  44.925 +     *         results in an <tt>IOException</tt>.
  44.926 +     * @throws NullPointerException if <code>os</code> is <code>null</code>,
  44.927 +     *         or if <code>encoding</code> is <code>null</code>.
  44.928 +     * @throws ClassCastException  if this <code>Properties</code> object
  44.929 +     *         contains any keys or values that are not
  44.930 +     *         <code>Strings</code>.
  44.931 +     * @see    #loadFromXML(InputStream)
  44.932 +     * @since 1.5
  44.933 +     */
  44.934 +    public void storeToXML(OutputStream os, String comment, String encoding)
  44.935 +        throws IOException
  44.936 +    {
  44.937 +        if (os == null)
  44.938 +            throw new NullPointerException();
  44.939 +        XMLUtils.save(this, os, comment, encoding);
  44.940 +    }
  44.941 +
  44.942 +    /**
  44.943 +     * Searches for the property with the specified key in this property list.
  44.944 +     * If the key is not found in this property list, the default property list,
  44.945 +     * and its defaults, recursively, are then checked. The method returns
  44.946 +     * <code>null</code> if the property is not found.
  44.947 +     *
  44.948 +     * @param   key   the property key.
  44.949 +     * @return  the value in this property list with the specified key value.
  44.950 +     * @see     #setProperty
  44.951 +     * @see     #defaults
  44.952 +     */
  44.953 +    public String getProperty(String key) {
  44.954 +        Object oval = super.get(key);
  44.955 +        String sval = (oval instanceof String) ? (String)oval : null;
  44.956 +        return ((sval == null) && (defaults != null)) ? defaults.getProperty(key) : sval;
  44.957 +    }
  44.958 +
  44.959 +    /**
  44.960 +     * Searches for the property with the specified key in this property list.
  44.961 +     * If the key is not found in this property list, the default property list,
  44.962 +     * and its defaults, recursively, are then checked. The method returns the
  44.963 +     * default value argument if the property is not found.
  44.964 +     *
  44.965 +     * @param   key            the hashtable key.
  44.966 +     * @param   defaultValue   a default value.
  44.967 +     *
  44.968 +     * @return  the value in this property list with the specified key value.
  44.969 +     * @see     #setProperty
  44.970 +     * @see     #defaults
  44.971 +     */
  44.972 +    public String getProperty(String key, String defaultValue) {
  44.973 +        String val = getProperty(key);
  44.974 +        return (val == null) ? defaultValue : val;
  44.975 +    }
  44.976 +
  44.977 +    /**
  44.978 +     * Returns an enumeration of all the keys in this property list,
  44.979 +     * including distinct keys in the default property list if a key
  44.980 +     * of the same name has not already been found from the main
  44.981 +     * properties list.
  44.982 +     *
  44.983 +     * @return  an enumeration of all the keys in this property list, including
  44.984 +     *          the keys in the default property list.
  44.985 +     * @throws  ClassCastException if any key in this property list
  44.986 +     *          is not a string.
  44.987 +     * @see     java.util.Enumeration
  44.988 +     * @see     java.util.Properties#defaults
  44.989 +     * @see     #stringPropertyNames
  44.990 +     */
  44.991 +    public Enumeration<?> propertyNames() {
  44.992 +        Hashtable h = new Hashtable();
  44.993 +        enumerate(h);
  44.994 +        return h.keys();
  44.995 +    }
  44.996 +
  44.997 +    /**
  44.998 +     * Returns a set of keys in this property list where
  44.999 +     * the key and its corresponding value are strings,
 44.1000 +     * including distinct keys in the default property list if a key
 44.1001 +     * of the same name has not already been found from the main
 44.1002 +     * properties list.  Properties whose key or value is not
 44.1003 +     * of type <tt>String</tt> are omitted.
 44.1004 +     * <p>
 44.1005 +     * The returned set is not backed by the <tt>Properties</tt> object.
 44.1006 +     * Changes to this <tt>Properties</tt> are not reflected in the set,
 44.1007 +     * or vice versa.
 44.1008 +     *
 44.1009 +     * @return  a set of keys in this property list where
 44.1010 +     *          the key and its corresponding value are strings,
 44.1011 +     *          including the keys in the default property list.
 44.1012 +     * @see     java.util.Properties#defaults
 44.1013 +     * @since   1.6
 44.1014 +     */
 44.1015 +    public Set<String> stringPropertyNames() {
 44.1016 +        Hashtable<String, String> h = new Hashtable<>();
 44.1017 +        enumerateStringProperties(h);
 44.1018 +        return h.keySet();
 44.1019 +    }
 44.1020 +
 44.1021 +    /**
 44.1022 +     * Prints this property list out to the specified output stream.
 44.1023 +     * This method is useful for debugging.
 44.1024 +     *
 44.1025 +     * @param   out   an output stream.
 44.1026 +     * @throws  ClassCastException if any key in this property list
 44.1027 +     *          is not a string.
 44.1028 +     */
 44.1029 +    public void list(PrintStream out) {
 44.1030 +        out.println("-- listing properties --");
 44.1031 +        Hashtable h = new Hashtable();
 44.1032 +        enumerate(h);
 44.1033 +        for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
 44.1034 +            String key = (String)e.nextElement();
 44.1035 +            String val = (String)h.get(key);
 44.1036 +            if (val.length() > 40) {
 44.1037 +                val = val.substring(0, 37) + "...";
 44.1038 +            }
 44.1039 +            out.println(key + "=" + val);
 44.1040 +        }
 44.1041 +    }
 44.1042 +
 44.1043 +    /**
 44.1044 +     * Prints this property list out to the specified output stream.
 44.1045 +     * This method is useful for debugging.
 44.1046 +     *
 44.1047 +     * @param   out   an output stream.
 44.1048 +     * @throws  ClassCastException if any key in this property list
 44.1049 +     *          is not a string.
 44.1050 +     * @since   JDK1.1
 44.1051 +     */
 44.1052 +    /*
 44.1053 +     * Rather than use an anonymous inner class to share common code, this
 44.1054 +     * method is duplicated in order to ensure that a non-1.1 compiler can
 44.1055 +     * compile this file.
 44.1056 +     */
 44.1057 +    public void list(PrintWriter out) {
 44.1058 +        out.println("-- listing properties --");
 44.1059 +        Hashtable h = new Hashtable();
 44.1060 +        enumerate(h);
 44.1061 +        for (Enumeration e = h.keys() ; e.hasMoreElements() ;) {
 44.1062 +            String key = (String)e.nextElement();
 44.1063 +            String val = (String)h.get(key);
 44.1064 +            if (val.length() > 40) {
 44.1065 +                val = val.substring(0, 37) + "...";
 44.1066 +            }
 44.1067 +            out.println(key + "=" + val);
 44.1068 +        }
 44.1069 +    }
 44.1070 +
 44.1071 +    /**
 44.1072 +     * Enumerates all key/value pairs in the specified hashtable.
 44.1073 +     * @param h the hashtable
 44.1074 +     * @throws ClassCastException if any of the property keys
 44.1075 +     *         is not of String type.
 44.1076 +     */
 44.1077 +    private synchronized void enumerate(Hashtable h) {
 44.1078 +        if (defaults != null) {
 44.1079 +            defaults.enumerate(h);
 44.1080 +        }
 44.1081 +        for (Enumeration e = keys() ; e.hasMoreElements() ;) {
 44.1082 +            String key = (String)e.nextElement();
 44.1083 +            h.put(key, get(key));
 44.1084 +        }
 44.1085 +    }
 44.1086 +
 44.1087 +    /**
 44.1088 +     * Enumerates all key/value pairs in the specified hashtable
 44.1089 +     * and omits the property if the key or value is not a string.
 44.1090 +     * @param h the hashtable
 44.1091 +     */
 44.1092 +    private synchronized void enumerateStringProperties(Hashtable<String, String> h) {
 44.1093 +        if (defaults != null) {
 44.1094 +            defaults.enumerateStringProperties(h);
 44.1095 +        }
 44.1096 +        for (Enumeration e = keys() ; e.hasMoreElements() ;) {
 44.1097 +            Object k = e.nextElement();
 44.1098 +            Object v = get(k);
 44.1099 +            if (k instanceof String && v instanceof String) {
 44.1100 +                h.put((String) k, (String) v);
 44.1101 +            }
 44.1102 +        }
 44.1103 +    }
 44.1104 +
 44.1105 +    /**
 44.1106 +     * Convert a nibble to a hex character
 44.1107 +     * @param   nibble  the nibble to convert.
 44.1108 +     */
 44.1109 +    private static char toHex(int nibble) {
 44.1110 +        return hexDigit[(nibble & 0xF)];
 44.1111 +    }
 44.1112 +
 44.1113 +    /** A table of hex digits */
 44.1114 +    private static final char[] hexDigit = {
 44.1115 +        '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
 44.1116 +    };
 44.1117 +}
    45.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    45.2 +++ b/rt/emul/compact/src/main/java/java/util/PropertyResourceBundle.java	Thu Oct 03 15:40:35 2013 +0200
    45.3 @@ -0,0 +1,190 @@
    45.4 +/*
    45.5 + * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
    45.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    45.7 + *
    45.8 + * This code is free software; you can redistribute it and/or modify it
    45.9 + * under the terms of the GNU General Public License version 2 only, as
   45.10 + * published by the Free Software Foundation.  Oracle designates this
   45.11 + * particular file as subject to the "Classpath" exception as provided
   45.12 + * by Oracle in the LICENSE file that accompanied this code.
   45.13 + *
   45.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   45.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   45.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   45.17 + * version 2 for more details (a copy is included in the LICENSE file that
   45.18 + * accompanied this code).
   45.19 + *
   45.20 + * You should have received a copy of the GNU General Public License version
   45.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   45.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   45.23 + *
   45.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   45.25 + * or visit www.oracle.com if you need additional information or have any
   45.26 + * questions.
   45.27 + */
   45.28 +
   45.29 +/*
   45.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   45.31 + * (C) Copyright IBM Corp. 1996 - 1998 - All Rights Reserved
   45.32 + *
   45.33 + * The original version of this source code and documentation
   45.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
   45.35 + * subsidiary of IBM. These materials are provided under terms
   45.36 + * of a License Agreement between Taligent and Sun. This technology
   45.37 + * is protected by multiple US and International patents.
   45.38 + *
   45.39 + * This notice and attribution to Taligent may not be removed.
   45.40 + * Taligent is a registered trademark of Taligent, Inc.
   45.41 + */
   45.42 +
   45.43 +package java.util;
   45.44 +
   45.45 +import java.io.InputStream;
   45.46 +import java.io.Reader;
   45.47 +import java.io.IOException;
   45.48 +import sun.util.ResourceBundleEnumeration;
   45.49 +
   45.50 +/**
   45.51 + * <code>PropertyResourceBundle</code> is a concrete subclass of
   45.52 + * <code>ResourceBundle</code> that manages resources for a locale
   45.53 + * using a set of static strings from a property file. See
   45.54 + * {@link ResourceBundle ResourceBundle} for more information about resource
   45.55 + * bundles.
   45.56 + *
   45.57 + * <p>
   45.58 + * Unlike other types of resource bundle, you don't subclass
   45.59 + * <code>PropertyResourceBundle</code>.  Instead, you supply properties
   45.60 + * files containing the resource data.  <code>ResourceBundle.getBundle</code>
   45.61 + * will automatically look for the appropriate properties file and create a
   45.62 + * <code>PropertyResourceBundle</code> that refers to it. See
   45.63 + * {@link ResourceBundle#getBundle(java.lang.String, java.util.Locale, java.lang.ClassLoader) ResourceBundle.getBundle}
   45.64 + * for a complete description of the search and instantiation strategy.
   45.65 + *
   45.66 + * <p>
   45.67 + * The following <a name="sample">example</a> shows a member of a resource
   45.68 + * bundle family with the base name "MyResources".
   45.69 + * The text defines the bundle "MyResources_de",
   45.70 + * the German member of the bundle family.
   45.71 + * This member is based on <code>PropertyResourceBundle</code>, and the text
   45.72 + * therefore is the content of the file "MyResources_de.properties"
   45.73 + * (a related <a href="ListResourceBundle.html#sample">example</a> shows
   45.74 + * how you can add bundles to this family that are implemented as subclasses
   45.75 + * of <code>ListResourceBundle</code>).
   45.76 + * The keys in this example are of the form "s1" etc. The actual
   45.77 + * keys are entirely up to your choice, so long as they are the same as
   45.78 + * the keys you use in your program to retrieve the objects from the bundle.
   45.79 + * Keys are case-sensitive.
   45.80 + * <blockquote>
   45.81 + * <pre>
   45.82 + * # MessageFormat pattern
   45.83 + * s1=Die Platte \"{1}\" enth&auml;lt {0}.
   45.84 + *
   45.85 + * # location of {0} in pattern
   45.86 + * s2=1
   45.87 + *
   45.88 + * # sample disk name
   45.89 + * s3=Meine Platte
   45.90 + *
   45.91 + * # first ChoiceFormat choice
   45.92 + * s4=keine Dateien
   45.93 + *
   45.94 + * # second ChoiceFormat choice
   45.95 + * s5=eine Datei
   45.96 + *
   45.97 + * # third ChoiceFormat choice
   45.98 + * s6={0,number} Dateien
   45.99 + *
  45.100 + * # sample date
  45.101 + * s7=3. M&auml;rz 1996
  45.102 + * </pre>
  45.103 + * </blockquote>
  45.104 + *
  45.105 + * <p>
  45.106 + * <strong>Note:</strong> PropertyResourceBundle can be constructed either
  45.107 + * from an InputStream or a Reader, which represents a property file.
  45.108 + * Constructing a PropertyResourceBundle instance from an InputStream requires
  45.109 + * that the input stream be encoded in ISO-8859-1.  In that case, characters
  45.110 + * that cannot be represented in ISO-8859-1 encoding must be represented by Unicode Escapes
  45.111 + * as defined in section 3.3 of
  45.112 + * <cite>The Java&trade; Language Specification</cite>
  45.113 + * whereas the other constructor which takes a Reader does not have that limitation.
  45.114 + *
  45.115 + * @see ResourceBundle
  45.116 + * @see ListResourceBundle
  45.117 + * @see Properties
  45.118 + * @since JDK1.1
  45.119 + */
  45.120 +public class PropertyResourceBundle extends ResourceBundle {
  45.121 +    /**
  45.122 +     * Creates a property resource bundle from an {@link java.io.InputStream
  45.123 +     * InputStream}.  The property file read with this constructor
  45.124 +     * must be encoded in ISO-8859-1.
  45.125 +     *
  45.126 +     * @param stream an InputStream that represents a property file
  45.127 +     *        to read from.
  45.128 +     * @throws IOException if an I/O error occurs
  45.129 +     * @throws NullPointerException if <code>stream</code> is null
  45.130 +     */
  45.131 +    public PropertyResourceBundle (InputStream stream) throws IOException {
  45.132 +        Properties properties = new Properties();
  45.133 +        properties.load(stream);
  45.134 +        lookup = new HashMap(properties);
  45.135 +    }
  45.136 +
  45.137 +    /**
  45.138 +     * Creates a property resource bundle from a {@link java.io.Reader
  45.139 +     * Reader}.  Unlike the constructor
  45.140 +     * {@link #PropertyResourceBundle(java.io.InputStream) PropertyResourceBundle(InputStream)},
  45.141 +     * there is no limitation as to the encoding of the input property file.
  45.142 +     *
  45.143 +     * @param reader a Reader that represents a property file to
  45.144 +     *        read from.
  45.145 +     * @throws IOException if an I/O error occurs
  45.146 +     * @throws NullPointerException if <code>reader</code> is null
  45.147 +     * @since 1.6
  45.148 +     */
  45.149 +    public PropertyResourceBundle (Reader reader) throws IOException {
  45.150 +        Properties properties = new Properties();
  45.151 +        properties.load(reader);
  45.152 +        lookup = new HashMap(properties);
  45.153 +    }
  45.154 +
  45.155 +    // Implements java.util.ResourceBundle.handleGetObject; inherits javadoc specification.
  45.156 +    public Object handleGetObject(String key) {
  45.157 +        if (key == null) {
  45.158 +            throw new NullPointerException();
  45.159 +        }
  45.160 +        return lookup.get(key);
  45.161 +    }
  45.162 +
  45.163 +    /**
  45.164 +     * Returns an <code>Enumeration</code> of the keys contained in
  45.165 +     * this <code>ResourceBundle</code> and its parent bundles.
  45.166 +     *
  45.167 +     * @return an <code>Enumeration</code> of the keys contained in
  45.168 +     *         this <code>ResourceBundle</code> and its parent bundles.
  45.169 +     * @see #keySet()
  45.170 +     */
  45.171 +    public Enumeration<String> getKeys() {
  45.172 +        ResourceBundle parent = this.parent;
  45.173 +        return new ResourceBundleEnumeration(lookup.keySet(),
  45.174 +                (parent != null) ? parent.getKeys() : null);
  45.175 +    }
  45.176 +
  45.177 +    /**
  45.178 +     * Returns a <code>Set</code> of the keys contained
  45.179 +     * <em>only</em> in this <code>ResourceBundle</code>.
  45.180 +     *
  45.181 +     * @return a <code>Set</code> of the keys contained only in this
  45.182 +     *         <code>ResourceBundle</code>
  45.183 +     * @since 1.6
  45.184 +     * @see #keySet()
  45.185 +     */
  45.186 +    protected Set<String> handleKeySet() {
  45.187 +        return lookup.keySet();
  45.188 +    }
  45.189 +
  45.190 +    // ==================privates====================
  45.191 +
  45.192 +    private Map<String,Object> lookup;
  45.193 +}
    46.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    46.2 +++ b/rt/emul/compact/src/main/java/java/util/ResourceBundle.java	Thu Oct 03 15:40:35 2013 +0200
    46.3 @@ -0,0 +1,2911 @@
    46.4 +/*
    46.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    46.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    46.7 + *
    46.8 + * This code is free software; you can redistribute it and/or modify it
    46.9 + * under the terms of the GNU General Public License version 2 only, as
   46.10 + * published by the Free Software Foundation.  Oracle designates this
   46.11 + * particular file as subject to the "Classpath" exception as provided
   46.12 + * by Oracle in the LICENSE file that accompanied this code.
   46.13 + *
   46.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   46.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   46.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   46.17 + * version 2 for more details (a copy is included in the LICENSE file that
   46.18 + * accompanied this code).
   46.19 + *
   46.20 + * You should have received a copy of the GNU General Public License version
   46.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   46.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   46.23 + *
   46.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   46.25 + * or visit www.oracle.com if you need additional information or have any
   46.26 + * questions.
   46.27 + */
   46.28 +
   46.29 +/*
   46.30 + * (C) Copyright Taligent, Inc. 1996, 1997 - All Rights Reserved
   46.31 + * (C) Copyright IBM Corp. 1996 - 1999 - All Rights Reserved
   46.32 + *
   46.33 + * The original version of this source code and documentation
   46.34 + * is copyrighted and owned by Taligent, Inc., a wholly-owned
   46.35 + * subsidiary of IBM. These materials are provided under terms
   46.36 + * of a License Agreement between Taligent and Sun. This technology
   46.37 + * is protected by multiple US and International patents.
   46.38 + *
   46.39 + * This notice and attribution to Taligent may not be removed.
   46.40 + * Taligent is a registered trademark of Taligent, Inc.
   46.41 + *
   46.42 + */
   46.43 +
   46.44 +package java.util;
   46.45 +
   46.46 +import java.io.IOException;
   46.47 +import java.io.InputStream;
   46.48 +import java.lang.ref.ReferenceQueue;
   46.49 +import java.lang.ref.SoftReference;
   46.50 +import java.lang.ref.WeakReference;
   46.51 +import java.net.JarURLConnection;
   46.52 +import java.net.URL;
   46.53 +import java.net.URLConnection;
   46.54 +import java.security.AccessController;
   46.55 +import java.security.PrivilegedAction;
   46.56 +import java.security.PrivilegedActionException;
   46.57 +import java.security.PrivilegedExceptionAction;
   46.58 +import java.util.concurrent.ConcurrentHashMap;
   46.59 +import java.util.concurrent.ConcurrentMap;
   46.60 +import java.util.jar.JarEntry;
   46.61 +
   46.62 +import sun.util.locale.BaseLocale;
   46.63 +import sun.util.locale.LocaleObjectCache;
   46.64 +
   46.65 +
   46.66 +/**
   46.67 + *
   46.68 + * Resource bundles contain locale-specific objects.  When your program needs a
   46.69 + * locale-specific resource, a <code>String</code> for example, your program can
   46.70 + * load it from the resource bundle that is appropriate for the current user's
   46.71 + * locale. In this way, you can write program code that is largely independent
   46.72 + * of the user's locale isolating most, if not all, of the locale-specific
   46.73 + * information in resource bundles.
   46.74 + *
   46.75 + * <p>
   46.76 + * This allows you to write programs that can:
   46.77 + * <UL type=SQUARE>
   46.78 + * <LI> be easily localized, or translated, into different languages
   46.79 + * <LI> handle multiple locales at once
   46.80 + * <LI> be easily modified later to support even more locales
   46.81 + * </UL>
   46.82 + *
   46.83 + * <P>
   46.84 + * Resource bundles belong to families whose members share a common base
   46.85 + * name, but whose names also have additional components that identify
   46.86 + * their locales. For example, the base name of a family of resource
   46.87 + * bundles might be "MyResources". The family should have a default
   46.88 + * resource bundle which simply has the same name as its family -
   46.89 + * "MyResources" - and will be used as the bundle of last resort if a
   46.90 + * specific locale is not supported. The family can then provide as
   46.91 + * many locale-specific members as needed, for example a German one
   46.92 + * named "MyResources_de".
   46.93 + *
   46.94 + * <P>
   46.95 + * Each resource bundle in a family contains the same items, but the items have
   46.96 + * been translated for the locale represented by that resource bundle.
   46.97 + * For example, both "MyResources" and "MyResources_de" may have a
   46.98 + * <code>String</code> that's used on a button for canceling operations.
   46.99 + * In "MyResources" the <code>String</code> may contain "Cancel" and in
  46.100 + * "MyResources_de" it may contain "Abbrechen".
  46.101 + *
  46.102 + * <P>
  46.103 + * If there are different resources for different countries, you
  46.104 + * can make specializations: for example, "MyResources_de_CH" contains objects for
  46.105 + * the German language (de) in Switzerland (CH). If you want to only
  46.106 + * modify some of the resources
  46.107 + * in the specialization, you can do so.
  46.108 + *
  46.109 + * <P>
  46.110 + * When your program needs a locale-specific object, it loads
  46.111 + * the <code>ResourceBundle</code> class using the
  46.112 + * {@link #getBundle(java.lang.String, java.util.Locale) getBundle}
  46.113 + * method:
  46.114 + * <blockquote>
  46.115 + * <pre>
  46.116 + * ResourceBundle myResources =
  46.117 + *      ResourceBundle.getBundle("MyResources", currentLocale);
  46.118 + * </pre>
  46.119 + * </blockquote>
  46.120 + *
  46.121 + * <P>
  46.122 + * Resource bundles contain key/value pairs. The keys uniquely
  46.123 + * identify a locale-specific object in the bundle. Here's an
  46.124 + * example of a <code>ListResourceBundle</code> that contains
  46.125 + * two key/value pairs:
  46.126 + * <blockquote>
  46.127 + * <pre>
  46.128 + * public class MyResources extends ListResourceBundle {
  46.129 + *     protected Object[][] getContents() {
  46.130 + *         return new Object[][] {
  46.131 + *             // LOCALIZE THE SECOND STRING OF EACH ARRAY (e.g., "OK")
  46.132 + *             {"OkKey", "OK"},
  46.133 + *             {"CancelKey", "Cancel"},
  46.134 + *             // END OF MATERIAL TO LOCALIZE
  46.135 + *        };
  46.136 + *     }
  46.137 + * }
  46.138 + * </pre>
  46.139 + * </blockquote>
  46.140 + * Keys are always <code>String</code>s.
  46.141 + * In this example, the keys are "OkKey" and "CancelKey".
  46.142 + * In the above example, the values
  46.143 + * are also <code>String</code>s--"OK" and "Cancel"--but
  46.144 + * they don't have to be. The values can be any type of object.
  46.145 + *
  46.146 + * <P>
  46.147 + * You retrieve an object from resource bundle using the appropriate
  46.148 + * getter method. Because "OkKey" and "CancelKey"
  46.149 + * are both strings, you would use <code>getString</code> to retrieve them:
  46.150 + * <blockquote>
  46.151 + * <pre>
  46.152 + * button1 = new Button(myResources.getString("OkKey"));
  46.153 + * button2 = new Button(myResources.getString("CancelKey"));
  46.154 + * </pre>
  46.155 + * </blockquote>
  46.156 + * The getter methods all require the key as an argument and return
  46.157 + * the object if found. If the object is not found, the getter method
  46.158 + * throws a <code>MissingResourceException</code>.
  46.159 + *
  46.160 + * <P>
  46.161 + * Besides <code>getString</code>, <code>ResourceBundle</code> also provides
  46.162 + * a method for getting string arrays, <code>getStringArray</code>,
  46.163 + * as well as a generic <code>getObject</code> method for any other
  46.164 + * type of object. When using <code>getObject</code>, you'll
  46.165 + * have to cast the result to the appropriate type. For example:
  46.166 + * <blockquote>
  46.167 + * <pre>
  46.168 + * int[] myIntegers = (int[]) myResources.getObject("intList");
  46.169 + * </pre>
  46.170 + * </blockquote>
  46.171 + *
  46.172 + * <P>
  46.173 + * The Java Platform provides two subclasses of <code>ResourceBundle</code>,
  46.174 + * <code>ListResourceBundle</code> and <code>PropertyResourceBundle</code>,
  46.175 + * that provide a fairly simple way to create resources.
  46.176 + * As you saw briefly in a previous example, <code>ListResourceBundle</code>
  46.177 + * manages its resource as a list of key/value pairs.
  46.178 + * <code>PropertyResourceBundle</code> uses a properties file to manage
  46.179 + * its resources.
  46.180 + *
  46.181 + * <p>
  46.182 + * If <code>ListResourceBundle</code> or <code>PropertyResourceBundle</code>
  46.183 + * do not suit your needs, you can write your own <code>ResourceBundle</code>
  46.184 + * subclass.  Your subclasses must override two methods: <code>handleGetObject</code>
  46.185 + * and <code>getKeys()</code>.
  46.186 + *
  46.187 + * <h4>ResourceBundle.Control</h4>
  46.188 + *
  46.189 + * The {@link ResourceBundle.Control} class provides information necessary
  46.190 + * to perform the bundle loading process by the <code>getBundle</code>
  46.191 + * factory methods that take a <code>ResourceBundle.Control</code>
  46.192 + * instance. You can implement your own subclass in order to enable
  46.193 + * non-standard resource bundle formats, change the search strategy, or
  46.194 + * define caching parameters. Refer to the descriptions of the class and the
  46.195 + * {@link #getBundle(String, Locale, ClassLoader, Control) getBundle}
  46.196 + * factory method for details.
  46.197 + *
  46.198 + * <h4>Cache Management</h4>
  46.199 + *
  46.200 + * Resource bundle instances created by the <code>getBundle</code> factory
  46.201 + * methods are cached by default, and the factory methods return the same
  46.202 + * resource bundle instance multiple times if it has been
  46.203 + * cached. <code>getBundle</code> clients may clear the cache, manage the
  46.204 + * lifetime of cached resource bundle instances using time-to-live values,
  46.205 + * or specify not to cache resource bundle instances. Refer to the
  46.206 + * descriptions of the {@linkplain #getBundle(String, Locale, ClassLoader,
  46.207 + * Control) <code>getBundle</code> factory method}, {@link
  46.208 + * #clearCache(ClassLoader) clearCache}, {@link
  46.209 + * Control#getTimeToLive(String, Locale)
  46.210 + * ResourceBundle.Control.getTimeToLive}, and {@link
  46.211 + * Control#needsReload(String, Locale, String, ClassLoader, ResourceBundle,
  46.212 + * long) ResourceBundle.Control.needsReload} for details.
  46.213 + *
  46.214 + * <h4>Example</h4>
  46.215 + *
  46.216 + * The following is a very simple example of a <code>ResourceBundle</code>
  46.217 + * subclass, <code>MyResources</code>, that manages two resources (for a larger number of
  46.218 + * resources you would probably use a <code>Map</code>).
  46.219 + * Notice that you don't need to supply a value if
  46.220 + * a "parent-level" <code>ResourceBundle</code> handles the same
  46.221 + * key with the same value (as for the okKey below).
  46.222 + * <blockquote>
  46.223 + * <pre>
  46.224 + * // default (English language, United States)
  46.225 + * public class MyResources extends ResourceBundle {
  46.226 + *     public Object handleGetObject(String key) {
  46.227 + *         if (key.equals("okKey")) return "Ok";
  46.228 + *         if (key.equals("cancelKey")) return "Cancel";
  46.229 + *         return null;
  46.230 + *     }
  46.231 + *
  46.232 + *     public Enumeration&lt;String&gt; getKeys() {
  46.233 + *         return Collections.enumeration(keySet());
  46.234 + *     }
  46.235 + *
  46.236 + *     // Overrides handleKeySet() so that the getKeys() implementation
  46.237 + *     // can rely on the keySet() value.
  46.238 + *     protected Set&lt;String&gt; handleKeySet() {
  46.239 + *         return new HashSet&lt;String&gt;(Arrays.asList("okKey", "cancelKey"));
  46.240 + *     }
  46.241 + * }
  46.242 + *
  46.243 + * // German language
  46.244 + * public class MyResources_de extends MyResources {
  46.245 + *     public Object handleGetObject(String key) {
  46.246 + *         // don't need okKey, since parent level handles it.
  46.247 + *         if (key.equals("cancelKey")) return "Abbrechen";
  46.248 + *         return null;
  46.249 + *     }
  46.250 + *
  46.251 + *     protected Set&lt;String&gt; handleKeySet() {
  46.252 + *         return new HashSet&lt;String&gt;(Arrays.asList("cancelKey"));
  46.253 + *     }
  46.254 + * }
  46.255 + * </pre>
  46.256 + * </blockquote>
  46.257 + * You do not have to restrict yourself to using a single family of
  46.258 + * <code>ResourceBundle</code>s. For example, you could have a set of bundles for
  46.259 + * exception messages, <code>ExceptionResources</code>
  46.260 + * (<code>ExceptionResources_fr</code>, <code>ExceptionResources_de</code>, ...),
  46.261 + * and one for widgets, <code>WidgetResource</code> (<code>WidgetResources_fr</code>,
  46.262 + * <code>WidgetResources_de</code>, ...); breaking up the resources however you like.
  46.263 + *
  46.264 + * @see ListResourceBundle
  46.265 + * @see PropertyResourceBundle
  46.266 + * @see MissingResourceException
  46.267 + * @since JDK1.1
  46.268 + */
  46.269 +public abstract class ResourceBundle {
  46.270 +
  46.271 +    /** initial size of the bundle cache */
  46.272 +    private static final int INITIAL_CACHE_SIZE = 32;
  46.273 +
  46.274 +    /** constant indicating that no resource bundle exists */
  46.275 +    private static final ResourceBundle NONEXISTENT_BUNDLE = new ResourceBundle() {
  46.276 +            public Enumeration<String> getKeys() { return null; }
  46.277 +            protected Object handleGetObject(String key) { return null; }
  46.278 +            public String toString() { return "NONEXISTENT_BUNDLE"; }
  46.279 +        };
  46.280 +
  46.281 +
  46.282 +    /**
  46.283 +     * The cache is a map from cache keys (with bundle base name, locale, and
  46.284 +     * class loader) to either a resource bundle or NONEXISTENT_BUNDLE wrapped by a
  46.285 +     * BundleReference.
  46.286 +     *
  46.287 +     * The cache is a ConcurrentMap, allowing the cache to be searched
  46.288 +     * concurrently by multiple threads.  This will also allow the cache keys
  46.289 +     * to be reclaimed along with the ClassLoaders they reference.
  46.290 +     *
  46.291 +     * This variable would be better named "cache", but we keep the old
  46.292 +     * name for compatibility with some workarounds for bug 4212439.
  46.293 +     */
  46.294 +    private static final ConcurrentMap<CacheKey, BundleReference> cacheList
  46.295 +        = new ConcurrentHashMap<>(INITIAL_CACHE_SIZE);
  46.296 +
  46.297 +    /**
  46.298 +     * Queue for reference objects referring to class loaders or bundles.
  46.299 +     */
  46.300 +    private static final ReferenceQueue referenceQueue = new ReferenceQueue();
  46.301 +
  46.302 +    /**
  46.303 +     * The parent bundle of this bundle.
  46.304 +     * The parent bundle is searched by {@link #getObject getObject}
  46.305 +     * when this bundle does not contain a particular resource.
  46.306 +     */
  46.307 +    protected ResourceBundle parent = null;
  46.308 +
  46.309 +    /**
  46.310 +     * The locale for this bundle.
  46.311 +     */
  46.312 +    private Locale locale = null;
  46.313 +
  46.314 +    /**
  46.315 +     * The base bundle name for this bundle.
  46.316 +     */
  46.317 +    private String name;
  46.318 +
  46.319 +    /**
  46.320 +     * The flag indicating this bundle has expired in the cache.
  46.321 +     */
  46.322 +    private volatile boolean expired;
  46.323 +
  46.324 +    /**
  46.325 +     * The back link to the cache key. null if this bundle isn't in
  46.326 +     * the cache (yet) or has expired.
  46.327 +     */
  46.328 +    private volatile CacheKey cacheKey;
  46.329 +
  46.330 +    /**
  46.331 +     * A Set of the keys contained only in this ResourceBundle.
  46.332 +     */
  46.333 +    private volatile Set<String> keySet;
  46.334 +
  46.335 +    /**
  46.336 +     * Sole constructor.  (For invocation by subclass constructors, typically
  46.337 +     * implicit.)
  46.338 +     */
  46.339 +    public ResourceBundle() {
  46.340 +    }
  46.341 +
  46.342 +    /**
  46.343 +     * Gets a string for the given key from this resource bundle or one of its parents.
  46.344 +     * Calling this method is equivalent to calling
  46.345 +     * <blockquote>
  46.346 +     * <code>(String) {@link #getObject(java.lang.String) getObject}(key)</code>.
  46.347 +     * </blockquote>
  46.348 +     *
  46.349 +     * @param key the key for the desired string
  46.350 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
  46.351 +     * @exception MissingResourceException if no object for the given key can be found
  46.352 +     * @exception ClassCastException if the object found for the given key is not a string
  46.353 +     * @return the string for the given key
  46.354 +     */
  46.355 +    public final String getString(String key) {
  46.356 +        return (String) getObject(key);
  46.357 +    }
  46.358 +
  46.359 +    /**
  46.360 +     * Gets a string array for the given key from this resource bundle or one of its parents.
  46.361 +     * Calling this method is equivalent to calling
  46.362 +     * <blockquote>
  46.363 +     * <code>(String[]) {@link #getObject(java.lang.String) getObject}(key)</code>.
  46.364 +     * </blockquote>
  46.365 +     *
  46.366 +     * @param key the key for the desired string array
  46.367 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
  46.368 +     * @exception MissingResourceException if no object for the given key can be found
  46.369 +     * @exception ClassCastException if the object found for the given key is not a string array
  46.370 +     * @return the string array for the given key
  46.371 +     */
  46.372 +    public final String[] getStringArray(String key) {
  46.373 +        return (String[]) getObject(key);
  46.374 +    }
  46.375 +
  46.376 +    /**
  46.377 +     * Gets an object for the given key from this resource bundle or one of its parents.
  46.378 +     * This method first tries to obtain the object from this resource bundle using
  46.379 +     * {@link #handleGetObject(java.lang.String) handleGetObject}.
  46.380 +     * If not successful, and the parent resource bundle is not null,
  46.381 +     * it calls the parent's <code>getObject</code> method.
  46.382 +     * If still not successful, it throws a MissingResourceException.
  46.383 +     *
  46.384 +     * @param key the key for the desired object
  46.385 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
  46.386 +     * @exception MissingResourceException if no object for the given key can be found
  46.387 +     * @return the object for the given key
  46.388 +     */
  46.389 +    public final Object getObject(String key) {
  46.390 +        Object obj = handleGetObject(key);
  46.391 +        if (obj == null) {
  46.392 +            if (parent != null) {
  46.393 +                obj = parent.getObject(key);
  46.394 +            }
  46.395 +            if (obj == null)
  46.396 +                throw new MissingResourceException("Can't find resource for bundle "
  46.397 +                                                   +this.getClass().getName()
  46.398 +                                                   +", key "+key,
  46.399 +                                                   this.getClass().getName(),
  46.400 +                                                   key);
  46.401 +        }
  46.402 +        return obj;
  46.403 +    }
  46.404 +
  46.405 +    /**
  46.406 +     * Returns the locale of this resource bundle. This method can be used after a
  46.407 +     * call to getBundle() to determine whether the resource bundle returned really
  46.408 +     * corresponds to the requested locale or is a fallback.
  46.409 +     *
  46.410 +     * @return the locale of this resource bundle
  46.411 +     */
  46.412 +    public Locale getLocale() {
  46.413 +        return locale;
  46.414 +    }
  46.415 +
  46.416 +    /*
  46.417 +     * Automatic determination of the ClassLoader to be used to load
  46.418 +     * resources on behalf of the client.  N.B. The client is getLoader's
  46.419 +     * caller's caller.
  46.420 +     */
  46.421 +    private static ClassLoader getLoader() {
  46.422 +        Class[] stack = getClassContext();
  46.423 +        /* Magic number 2 identifies our caller's caller */
  46.424 +        Class c = stack[2];
  46.425 +        ClassLoader cl = (c == null) ? null : c.getClassLoader();
  46.426 +        if (cl == null) {
  46.427 +            // When the caller's loader is the boot class loader, cl is null
  46.428 +            // here. In that case, ClassLoader.getSystemClassLoader() may
  46.429 +            // return the same class loader that the application is
  46.430 +            // using. We therefore use a wrapper ClassLoader to create a
  46.431 +            // separate scope for bundles loaded on behalf of the Java
  46.432 +            // runtime so that these bundles cannot be returned from the
  46.433 +            // cache to the application (5048280).
  46.434 +            cl = RBClassLoader.INSTANCE;
  46.435 +        }
  46.436 +        return cl;
  46.437 +    }
  46.438 +
  46.439 +    private static native Class[] getClassContext();
  46.440 +
  46.441 +    /**
  46.442 +     * A wrapper of ClassLoader.getSystemClassLoader().
  46.443 +     */
  46.444 +    private static class RBClassLoader extends ClassLoader {
  46.445 +        private static final RBClassLoader INSTANCE = AccessController.doPrivileged(
  46.446 +                    new PrivilegedAction<RBClassLoader>() {
  46.447 +                        public RBClassLoader run() {
  46.448 +                            return new RBClassLoader();
  46.449 +                        }
  46.450 +                    });
  46.451 +        private static final ClassLoader loader = ClassLoader.getSystemClassLoader();
  46.452 +
  46.453 +        private RBClassLoader() {
  46.454 +        }
  46.455 +        public Class<?> loadClass(String name) throws ClassNotFoundException {
  46.456 +            if (loader != null) {
  46.457 +                return loader.loadClass(name);
  46.458 +            }
  46.459 +            return Class.forName(name);
  46.460 +        }
  46.461 +        public URL getResource(String name) {
  46.462 +            if (loader != null) {
  46.463 +                return loader.getResource(name);
  46.464 +            }
  46.465 +            return ClassLoader.getSystemResource(name);
  46.466 +        }
  46.467 +        public InputStream getResourceAsStream(String name) {
  46.468 +            if (loader != null) {
  46.469 +                return loader.getResourceAsStream(name);
  46.470 +            }
  46.471 +            return ClassLoader.getSystemResourceAsStream(name);
  46.472 +        }
  46.473 +    }
  46.474 +
  46.475 +    /**
  46.476 +     * Sets the parent bundle of this bundle.
  46.477 +     * The parent bundle is searched by {@link #getObject getObject}
  46.478 +     * when this bundle does not contain a particular resource.
  46.479 +     *
  46.480 +     * @param parent this bundle's parent bundle.
  46.481 +     */
  46.482 +    protected void setParent(ResourceBundle parent) {
  46.483 +        assert parent != NONEXISTENT_BUNDLE;
  46.484 +        this.parent = parent;
  46.485 +    }
  46.486 +
  46.487 +    /**
  46.488 +     * Key used for cached resource bundles.  The key checks the base
  46.489 +     * name, the locale, and the class loader to determine if the
  46.490 +     * resource is a match to the requested one. The loader may be
  46.491 +     * null, but the base name and the locale must have a non-null
  46.492 +     * value.
  46.493 +     */
  46.494 +    private static final class CacheKey implements Cloneable {
  46.495 +        // These three are the actual keys for lookup in Map.
  46.496 +        private String name;
  46.497 +        private Locale locale;
  46.498 +        private LoaderReference loaderRef;
  46.499 +
  46.500 +        // bundle format which is necessary for calling
  46.501 +        // Control.needsReload().
  46.502 +        private String format;
  46.503 +
  46.504 +        // These time values are in CacheKey so that NONEXISTENT_BUNDLE
  46.505 +        // doesn't need to be cloned for caching.
  46.506 +
  46.507 +        // The time when the bundle has been loaded
  46.508 +        private volatile long loadTime;
  46.509 +
  46.510 +        // The time when the bundle expires in the cache, or either
  46.511 +        // Control.TTL_DONT_CACHE or Control.TTL_NO_EXPIRATION_CONTROL.
  46.512 +        private volatile long expirationTime;
  46.513 +
  46.514 +        // Placeholder for an error report by a Throwable
  46.515 +        private Throwable cause;
  46.516 +
  46.517 +        // Hash code value cache to avoid recalculating the hash code
  46.518 +        // of this instance.
  46.519 +        private int hashCodeCache;
  46.520 +
  46.521 +        CacheKey(String baseName, Locale locale, ClassLoader loader) {
  46.522 +            this.name = baseName;
  46.523 +            this.locale = locale;
  46.524 +            if (loader == null) {
  46.525 +                this.loaderRef = null;
  46.526 +            } else {
  46.527 +                loaderRef = new LoaderReference(loader, referenceQueue, this);
  46.528 +            }
  46.529 +            calculateHashCode();
  46.530 +        }
  46.531 +
  46.532 +        String getName() {
  46.533 +            return name;
  46.534 +        }
  46.535 +
  46.536 +        CacheKey setName(String baseName) {
  46.537 +            if (!this.name.equals(baseName)) {
  46.538 +                this.name = baseName;
  46.539 +                calculateHashCode();
  46.540 +            }
  46.541 +            return this;
  46.542 +        }
  46.543 +
  46.544 +        Locale getLocale() {
  46.545 +            return locale;
  46.546 +        }
  46.547 +
  46.548 +        CacheKey setLocale(Locale locale) {
  46.549 +            if (!this.locale.equals(locale)) {
  46.550 +                this.locale = locale;
  46.551 +                calculateHashCode();
  46.552 +            }
  46.553 +            return this;
  46.554 +        }
  46.555 +
  46.556 +        ClassLoader getLoader() {
  46.557 +            return (loaderRef != null) ? loaderRef.get() : null;
  46.558 +        }
  46.559 +
  46.560 +        public boolean equals(Object other) {
  46.561 +            if (this == other) {
  46.562 +                return true;
  46.563 +            }
  46.564 +            try {
  46.565 +                final CacheKey otherEntry = (CacheKey)other;
  46.566 +                //quick check to see if they are not equal
  46.567 +                if (hashCodeCache != otherEntry.hashCodeCache) {
  46.568 +                    return false;
  46.569 +                }
  46.570 +                //are the names the same?
  46.571 +                if (!name.equals(otherEntry.name)) {
  46.572 +                    return false;
  46.573 +                }
  46.574 +                // are the locales the same?
  46.575 +                if (!locale.equals(otherEntry.locale)) {
  46.576 +                    return false;
  46.577 +                }
  46.578 +                //are refs (both non-null) or (both null)?
  46.579 +                if (loaderRef == null) {
  46.580 +                    return otherEntry.loaderRef == null;
  46.581 +                }
  46.582 +                ClassLoader loader = loaderRef.get();
  46.583 +                return (otherEntry.loaderRef != null)
  46.584 +                        // with a null reference we can no longer find
  46.585 +                        // out which class loader was referenced; so
  46.586 +                        // treat it as unequal
  46.587 +                        && (loader != null)
  46.588 +                        && (loader == otherEntry.loaderRef.get());
  46.589 +            } catch (NullPointerException e) {
  46.590 +            } catch (ClassCastException e) {
  46.591 +            }
  46.592 +            return false;
  46.593 +        }
  46.594 +
  46.595 +        public int hashCode() {
  46.596 +            return hashCodeCache;
  46.597 +        }
  46.598 +
  46.599 +        private void calculateHashCode() {
  46.600 +            hashCodeCache = name.hashCode() << 3;
  46.601 +            hashCodeCache ^= locale.hashCode();
  46.602 +            ClassLoader loader = getLoader();
  46.603 +            if (loader != null) {
  46.604 +                hashCodeCache ^= loader.hashCode();
  46.605 +            }
  46.606 +        }
  46.607 +
  46.608 +        public Object clone() {
  46.609 +            try {
  46.610 +                CacheKey clone = (CacheKey) super.clone();
  46.611 +                if (loaderRef != null) {
  46.612 +                    clone.loaderRef = new LoaderReference(loaderRef.get(),
  46.613 +                                                          referenceQueue, clone);
  46.614 +                }
  46.615 +                // Clear the reference to a Throwable
  46.616 +                clone.cause = null;
  46.617 +                return clone;
  46.618 +            } catch (CloneNotSupportedException e) {
  46.619 +                //this should never happen
  46.620 +                throw new InternalError();
  46.621 +            }
  46.622 +        }
  46.623 +
  46.624 +        String getFormat() {
  46.625 +            return format;
  46.626 +        }
  46.627 +
  46.628 +        void setFormat(String format) {
  46.629 +            this.format = format;
  46.630 +        }
  46.631 +
  46.632 +        private void setCause(Throwable cause) {
  46.633 +            if (this.cause == null) {
  46.634 +                this.cause = cause;
  46.635 +            } else {
  46.636 +                // Override the cause if the previous one is
  46.637 +                // ClassNotFoundException.
  46.638 +                if (this.cause instanceof ClassNotFoundException) {
  46.639 +                    this.cause = cause;
  46.640 +                }
  46.641 +            }
  46.642 +        }
  46.643 +
  46.644 +        private Throwable getCause() {
  46.645 +            return cause;
  46.646 +        }
  46.647 +
  46.648 +        public String toString() {
  46.649 +            String l = locale.toString();
  46.650 +            if (l.length() == 0) {
  46.651 +                if (locale.getVariant().length() != 0) {
  46.652 +                    l = "__" + locale.getVariant();
  46.653 +                } else {
  46.654 +                    l = "\"\"";
  46.655 +                }
  46.656 +            }
  46.657 +            return "CacheKey[" + name + ", lc=" + l + ", ldr=" + getLoader()
  46.658 +                + "(format=" + format + ")]";
  46.659 +        }
  46.660 +    }
  46.661 +
  46.662 +    /**
  46.663 +     * The common interface to get a CacheKey in LoaderReference and
  46.664 +     * BundleReference.
  46.665 +     */
  46.666 +    private static interface CacheKeyReference {
  46.667 +        public CacheKey getCacheKey();
  46.668 +    }
  46.669 +
  46.670 +    /**
  46.671 +     * References to class loaders are weak references, so that they can be
  46.672 +     * garbage collected when nobody else is using them. The ResourceBundle
  46.673 +     * class has no reason to keep class loaders alive.
  46.674 +     */
  46.675 +    private static final class LoaderReference extends WeakReference<ClassLoader>
  46.676 +                                               implements CacheKeyReference {
  46.677 +        private CacheKey cacheKey;
  46.678 +
  46.679 +        LoaderReference(ClassLoader referent, ReferenceQueue q, CacheKey key) {
  46.680 +            super(referent, q);
  46.681 +            cacheKey = key;
  46.682 +        }
  46.683 +
  46.684 +        public CacheKey getCacheKey() {
  46.685 +            return cacheKey;
  46.686 +        }
  46.687 +    }
  46.688 +
  46.689 +    /**
  46.690 +     * References to bundles are soft references so that they can be garbage
  46.691 +     * collected when they have no hard references.
  46.692 +     */
  46.693 +    private static final class BundleReference extends SoftReference<ResourceBundle>
  46.694 +                                               implements CacheKeyReference {
  46.695 +        private CacheKey cacheKey;
  46.696 +
  46.697 +        BundleReference(ResourceBundle referent, ReferenceQueue q, CacheKey key) {
  46.698 +            super(referent, q);
  46.699 +            cacheKey = key;
  46.700 +        }
  46.701 +
  46.702 +        public CacheKey getCacheKey() {
  46.703 +            return cacheKey;
  46.704 +        }
  46.705 +    }
  46.706 +
  46.707 +    /**
  46.708 +     * Gets a resource bundle using the specified base name, the default locale,
  46.709 +     * and the caller's class loader. Calling this method is equivalent to calling
  46.710 +     * <blockquote>
  46.711 +     * <code>getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())</code>,
  46.712 +     * </blockquote>
  46.713 +     * except that <code>getClassLoader()</code> is run with the security
  46.714 +     * privileges of <code>ResourceBundle</code>.
  46.715 +     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
  46.716 +     * for a complete description of the search and instantiation strategy.
  46.717 +     *
  46.718 +     * @param baseName the base name of the resource bundle, a fully qualified class name
  46.719 +     * @exception java.lang.NullPointerException
  46.720 +     *     if <code>baseName</code> is <code>null</code>
  46.721 +     * @exception MissingResourceException
  46.722 +     *     if no resource bundle for the specified base name can be found
  46.723 +     * @return a resource bundle for the given base name and the default locale
  46.724 +     */
  46.725 +    public static final ResourceBundle getBundle(String baseName)
  46.726 +    {
  46.727 +        return getBundleImpl(baseName, Locale.getDefault(),
  46.728 +                             /* must determine loader here, else we break stack invariant */
  46.729 +                             getLoader(),
  46.730 +                             Control.INSTANCE);
  46.731 +    }
  46.732 +
  46.733 +    /**
  46.734 +     * Returns a resource bundle using the specified base name, the
  46.735 +     * default locale and the specified control. Calling this method
  46.736 +     * is equivalent to calling
  46.737 +     * <pre>
  46.738 +     * getBundle(baseName, Locale.getDefault(),
  46.739 +     *           this.getClass().getClassLoader(), control),
  46.740 +     * </pre>
  46.741 +     * except that <code>getClassLoader()</code> is run with the security
  46.742 +     * privileges of <code>ResourceBundle</code>.  See {@link
  46.743 +     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
  46.744 +     * complete description of the resource bundle loading process with a
  46.745 +     * <code>ResourceBundle.Control</code>.
  46.746 +     *
  46.747 +     * @param baseName
  46.748 +     *        the base name of the resource bundle, a fully qualified class
  46.749 +     *        name
  46.750 +     * @param control
  46.751 +     *        the control which gives information for the resource bundle
  46.752 +     *        loading process
  46.753 +     * @return a resource bundle for the given base name and the default
  46.754 +     *        locale
  46.755 +     * @exception NullPointerException
  46.756 +     *        if <code>baseName</code> or <code>control</code> is
  46.757 +     *        <code>null</code>
  46.758 +     * @exception MissingResourceException
  46.759 +     *        if no resource bundle for the specified base name can be found
  46.760 +     * @exception IllegalArgumentException
  46.761 +     *        if the given <code>control</code> doesn't perform properly
  46.762 +     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
  46.763 +     *        Note that validation of <code>control</code> is performed as
  46.764 +     *        needed.
  46.765 +     * @since 1.6
  46.766 +     */
  46.767 +    public static final ResourceBundle getBundle(String baseName,
  46.768 +                                                 Control control) {
  46.769 +        return getBundleImpl(baseName, Locale.getDefault(),
  46.770 +                             /* must determine loader here, else we break stack invariant */
  46.771 +                             getLoader(),
  46.772 +                             control);
  46.773 +    }
  46.774 +
  46.775 +    /**
  46.776 +     * Gets a resource bundle using the specified base name and locale,
  46.777 +     * and the caller's class loader. Calling this method is equivalent to calling
  46.778 +     * <blockquote>
  46.779 +     * <code>getBundle(baseName, locale, this.getClass().getClassLoader())</code>,
  46.780 +     * </blockquote>
  46.781 +     * except that <code>getClassLoader()</code> is run with the security
  46.782 +     * privileges of <code>ResourceBundle</code>.
  46.783 +     * See {@link #getBundle(String, Locale, ClassLoader) getBundle}
  46.784 +     * for a complete description of the search and instantiation strategy.
  46.785 +     *
  46.786 +     * @param baseName
  46.787 +     *        the base name of the resource bundle, a fully qualified class name
  46.788 +     * @param locale
  46.789 +     *        the locale for which a resource bundle is desired
  46.790 +     * @exception NullPointerException
  46.791 +     *        if <code>baseName</code> or <code>locale</code> is <code>null</code>
  46.792 +     * @exception MissingResourceException
  46.793 +     *        if no resource bundle for the specified base name can be found
  46.794 +     * @return a resource bundle for the given base name and locale
  46.795 +     */
  46.796 +    public static final ResourceBundle getBundle(String baseName,
  46.797 +                                                 Locale locale)
  46.798 +    {
  46.799 +        return getBundleImpl(baseName, locale,
  46.800 +                             /* must determine loader here, else we break stack invariant */
  46.801 +                             getLoader(),
  46.802 +                             Control.INSTANCE);
  46.803 +    }
  46.804 +
  46.805 +    /**
  46.806 +     * Returns a resource bundle using the specified base name, target
  46.807 +     * locale and control, and the caller's class loader. Calling this
  46.808 +     * method is equivalent to calling
  46.809 +     * <pre>
  46.810 +     * getBundle(baseName, targetLocale, this.getClass().getClassLoader(),
  46.811 +     *           control),
  46.812 +     * </pre>
  46.813 +     * except that <code>getClassLoader()</code> is run with the security
  46.814 +     * privileges of <code>ResourceBundle</code>.  See {@link
  46.815 +     * #getBundle(String, Locale, ClassLoader, Control) getBundle} for the
  46.816 +     * complete description of the resource bundle loading process with a
  46.817 +     * <code>ResourceBundle.Control</code>.
  46.818 +     *
  46.819 +     * @param baseName
  46.820 +     *        the base name of the resource bundle, a fully qualified
  46.821 +     *        class name
  46.822 +     * @param targetLocale
  46.823 +     *        the locale for which a resource bundle is desired
  46.824 +     * @param control
  46.825 +     *        the control which gives information for the resource
  46.826 +     *        bundle loading process
  46.827 +     * @return a resource bundle for the given base name and a
  46.828 +     *        <code>Locale</code> in <code>locales</code>
  46.829 +     * @exception NullPointerException
  46.830 +     *        if <code>baseName</code>, <code>locales</code> or
  46.831 +     *        <code>control</code> is <code>null</code>
  46.832 +     * @exception MissingResourceException
  46.833 +     *        if no resource bundle for the specified base name in any
  46.834 +     *        of the <code>locales</code> can be found.
  46.835 +     * @exception IllegalArgumentException
  46.836 +     *        if the given <code>control</code> doesn't perform properly
  46.837 +     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
  46.838 +     *        Note that validation of <code>control</code> is performed as
  46.839 +     *        needed.
  46.840 +     * @since 1.6
  46.841 +     */
  46.842 +    public static final ResourceBundle getBundle(String baseName, Locale targetLocale,
  46.843 +                                                 Control control) {
  46.844 +        return getBundleImpl(baseName, targetLocale,
  46.845 +                             /* must determine loader here, else we break stack invariant */
  46.846 +                             getLoader(),
  46.847 +                             control);
  46.848 +    }
  46.849 +
  46.850 +    /**
  46.851 +     * Gets a resource bundle using the specified base name, locale, and class
  46.852 +     * loader.
  46.853 +     *
  46.854 +     * <p><a name="default_behavior"/>This method behaves the same as calling
  46.855 +     * {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
  46.856 +     * default instance of {@link Control}. The following describes this behavior.
  46.857 +     *
  46.858 +     * <p><code>getBundle</code> uses the base name, the specified locale, and
  46.859 +     * the default locale (obtained from {@link java.util.Locale#getDefault()
  46.860 +     * Locale.getDefault}) to generate a sequence of <a
  46.861 +     * name="candidates"><em>candidate bundle names</em></a>.  If the specified
  46.862 +     * locale's language, script, country, and variant are all empty strings,
  46.863 +     * then the base name is the only candidate bundle name.  Otherwise, a list
  46.864 +     * of candidate locales is generated from the attribute values of the
  46.865 +     * specified locale (language, script, country and variant) and appended to
  46.866 +     * the base name.  Typically, this will look like the following:
  46.867 +     *
  46.868 +     * <pre>
  46.869 +     *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
  46.870 +     *     baseName + "_" + language + "_" + script + "_" + country
  46.871 +     *     baseName + "_" + language + "_" + script
  46.872 +     *     baseName + "_" + language + "_" + country + "_" + variant
  46.873 +     *     baseName + "_" + language + "_" + country
  46.874 +     *     baseName + "_" + language
  46.875 +     * </pre>
  46.876 +     *
  46.877 +     * <p>Candidate bundle names where the final component is an empty string
  46.878 +     * are omitted, along with the underscore.  For example, if country is an
  46.879 +     * empty string, the second and the fifth candidate bundle names above
  46.880 +     * would be omitted.  Also, if script is an empty string, the candidate names
  46.881 +     * including script are omitted.  For example, a locale with language "de"
  46.882 +     * and variant "JAVA" will produce candidate names with base name
  46.883 +     * "MyResource" below.
  46.884 +     *
  46.885 +     * <pre>
  46.886 +     *     MyResource_de__JAVA
  46.887 +     *     MyResource_de
  46.888 +     * </pre>
  46.889 +     *
  46.890 +     * In the case that the variant contains one or more underscores ('_'), a
  46.891 +     * sequence of bundle names generated by truncating the last underscore and
  46.892 +     * the part following it is inserted after a candidate bundle name with the
  46.893 +     * original variant.  For example, for a locale with language "en", script
  46.894 +     * "Latn, country "US" and variant "WINDOWS_VISTA", and bundle base name
  46.895 +     * "MyResource", the list of candidate bundle names below is generated:
  46.896 +     *
  46.897 +     * <pre>
  46.898 +     * MyResource_en_Latn_US_WINDOWS_VISTA
  46.899 +     * MyResource_en_Latn_US_WINDOWS
  46.900 +     * MyResource_en_Latn_US
  46.901 +     * MyResource_en_Latn
  46.902 +     * MyResource_en_US_WINDOWS_VISTA
  46.903 +     * MyResource_en_US_WINDOWS
  46.904 +     * MyResource_en_US
  46.905 +     * MyResource_en
  46.906 +     * </pre>
  46.907 +     *
  46.908 +     * <blockquote><b>Note:</b> For some <code>Locale</code>s, the list of
  46.909 +     * candidate bundle names contains extra names, or the order of bundle names
  46.910 +     * is slightly modified.  See the description of the default implementation
  46.911 +     * of {@link Control#getCandidateLocales(String, Locale)
  46.912 +     * getCandidateLocales} for details.</blockquote>
  46.913 +     *
  46.914 +     * <p><code>getBundle</code> then iterates over the candidate bundle names
  46.915 +     * to find the first one for which it can <em>instantiate</em> an actual
  46.916 +     * resource bundle. It uses the default controls' {@link Control#getFormats
  46.917 +     * getFormats} method, which generates two bundle names for each generated
  46.918 +     * name, the first a class name and the second a properties file name. For
  46.919 +     * each candidate bundle name, it attempts to create a resource bundle:
  46.920 +     *
  46.921 +     * <ul><li>First, it attempts to load a class using the generated class name.
  46.922 +     * If such a class can be found and loaded using the specified class
  46.923 +     * loader, is assignment compatible with ResourceBundle, is accessible from
  46.924 +     * ResourceBundle, and can be instantiated, <code>getBundle</code> creates a
  46.925 +     * new instance of this class and uses it as the <em>result resource
  46.926 +     * bundle</em>.
  46.927 +     *
  46.928 +     * <li>Otherwise, <code>getBundle</code> attempts to locate a property
  46.929 +     * resource file using the generated properties file name.  It generates a
  46.930 +     * path name from the candidate bundle name by replacing all "." characters
  46.931 +     * with "/" and appending the string ".properties".  It attempts to find a
  46.932 +     * "resource" with this name using {@link
  46.933 +     * java.lang.ClassLoader#getResource(java.lang.String)
  46.934 +     * ClassLoader.getResource}.  (Note that a "resource" in the sense of
  46.935 +     * <code>getResource</code> has nothing to do with the contents of a
  46.936 +     * resource bundle, it is just a container of data, such as a file.)  If it
  46.937 +     * finds a "resource", it attempts to create a new {@link
  46.938 +     * PropertyResourceBundle} instance from its contents.  If successful, this
  46.939 +     * instance becomes the <em>result resource bundle</em>.  </ul>
  46.940 +     *
  46.941 +     * <p>This continues until a result resource bundle is instantiated or the
  46.942 +     * list of candidate bundle names is exhausted.  If no matching resource
  46.943 +     * bundle is found, the default control's {@link Control#getFallbackLocale
  46.944 +     * getFallbackLocale} method is called, which returns the current default
  46.945 +     * locale.  A new sequence of candidate locale names is generated using this
  46.946 +     * locale and and searched again, as above.
  46.947 +     *
  46.948 +     * <p>If still no result bundle is found, the base name alone is looked up. If
  46.949 +     * this still fails, a <code>MissingResourceException</code> is thrown.
  46.950 +     *
  46.951 +     * <p><a name="parent_chain"/> Once a result resource bundle has been found,
  46.952 +     * its <em>parent chain</em> is instantiated.  If the result bundle already
  46.953 +     * has a parent (perhaps because it was returned from a cache) the chain is
  46.954 +     * complete.
  46.955 +     *
  46.956 +     * <p>Otherwise, <code>getBundle</code> examines the remainder of the
  46.957 +     * candidate locale list that was used during the pass that generated the
  46.958 +     * result resource bundle.  (As before, candidate bundle names where the
  46.959 +     * final component is an empty string are omitted.)  When it comes to the
  46.960 +     * end of the candidate list, it tries the plain bundle name.  With each of the
  46.961 +     * candidate bundle names it attempts to instantiate a resource bundle (first
  46.962 +     * looking for a class and then a properties file, as described above).
  46.963 +     *
  46.964 +     * <p>Whenever it succeeds, it calls the previously instantiated resource
  46.965 +     * bundle's {@link #setParent(java.util.ResourceBundle) setParent} method
  46.966 +     * with the new resource bundle.  This continues until the list of names
  46.967 +     * is exhausted or the current bundle already has a non-null parent.
  46.968 +     *
  46.969 +     * <p>Once the parent chain is complete, the bundle is returned.
  46.970 +     *
  46.971 +     * <p><b>Note:</b> <code>getBundle</code> caches instantiated resource
  46.972 +     * bundles and might return the same resource bundle instance multiple times.
  46.973 +     *
  46.974 +     * <p><b>Note:</b>The <code>baseName</code> argument should be a fully
  46.975 +     * qualified class name. However, for compatibility with earlier versions,
  46.976 +     * Sun's Java SE Runtime Environments do not verify this, and so it is
  46.977 +     * possible to access <code>PropertyResourceBundle</code>s by specifying a
  46.978 +     * path name (using "/") instead of a fully qualified class name (using
  46.979 +     * ".").
  46.980 +     *
  46.981 +     * <p><a name="default_behavior_example"/>
  46.982 +     * <strong>Example:</strong>
  46.983 +     * <p>
  46.984 +     * The following class and property files are provided:
  46.985 +     * <pre>
  46.986 +     *     MyResources.class
  46.987 +     *     MyResources.properties
  46.988 +     *     MyResources_fr.properties
  46.989 +     *     MyResources_fr_CH.class
  46.990 +     *     MyResources_fr_CH.properties
  46.991 +     *     MyResources_en.properties
  46.992 +     *     MyResources_es_ES.class
  46.993 +     * </pre>
  46.994 +     *
  46.995 +     * The contents of all files are valid (that is, public non-abstract
  46.996 +     * subclasses of <code>ResourceBundle</code> for the ".class" files,
  46.997 +     * syntactically correct ".properties" files).  The default locale is
  46.998 +     * <code>Locale("en", "GB")</code>.
  46.999 +     *
 46.1000 +     * <p>Calling <code>getBundle</code> with the locale arguments below will
 46.1001 +     * instantiate resource bundles as follows:
 46.1002 +     *
 46.1003 +     * <table>
 46.1004 +     * <tr><td>Locale("fr", "CH")</td><td>MyResources_fr_CH.class, parent MyResources_fr.properties, parent MyResources.class</td></tr>
 46.1005 +     * <tr><td>Locale("fr", "FR")</td><td>MyResources_fr.properties, parent MyResources.class</td></tr>
 46.1006 +     * <tr><td>Locale("de", "DE")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
 46.1007 +     * <tr><td>Locale("en", "US")</td><td>MyResources_en.properties, parent MyResources.class</td></tr>
 46.1008 +     * <tr><td>Locale("es", "ES")</td><td>MyResources_es_ES.class, parent MyResources.class</td></tr>
 46.1009 +     * </table>
 46.1010 +     *
 46.1011 +     * <p>The file MyResources_fr_CH.properties is never used because it is
 46.1012 +     * hidden by the MyResources_fr_CH.class. Likewise, MyResources.properties
 46.1013 +     * is also hidden by MyResources.class.
 46.1014 +     *
 46.1015 +     * @param baseName the base name of the resource bundle, a fully qualified class name
 46.1016 +     * @param locale the locale for which a resource bundle is desired
 46.1017 +     * @param loader the class loader from which to load the resource bundle
 46.1018 +     * @return a resource bundle for the given base name and locale
 46.1019 +     * @exception java.lang.NullPointerException
 46.1020 +     *        if <code>baseName</code>, <code>locale</code>, or <code>loader</code> is <code>null</code>
 46.1021 +     * @exception MissingResourceException
 46.1022 +     *        if no resource bundle for the specified base name can be found
 46.1023 +     * @since 1.2
 46.1024 +     */
 46.1025 +    public static ResourceBundle getBundle(String baseName, Locale locale,
 46.1026 +                                           ClassLoader loader)
 46.1027 +    {
 46.1028 +        if (loader == null) {
 46.1029 +            throw new NullPointerException();
 46.1030 +        }
 46.1031 +        return getBundleImpl(baseName, locale, loader, Control.INSTANCE);
 46.1032 +    }
 46.1033 +
 46.1034 +    /**
 46.1035 +     * Returns a resource bundle using the specified base name, target
 46.1036 +     * locale, class loader and control. Unlike the {@linkplain
 46.1037 +     * #getBundle(String, Locale, ClassLoader) <code>getBundle</code>
 46.1038 +     * factory methods with no <code>control</code> argument}, the given
 46.1039 +     * <code>control</code> specifies how to locate and instantiate resource
 46.1040 +     * bundles. Conceptually, the bundle loading process with the given
 46.1041 +     * <code>control</code> is performed in the following steps.
 46.1042 +     *
 46.1043 +     * <p>
 46.1044 +     * <ol>
 46.1045 +     * <li>This factory method looks up the resource bundle in the cache for
 46.1046 +     * the specified <code>baseName</code>, <code>targetLocale</code> and
 46.1047 +     * <code>loader</code>.  If the requested resource bundle instance is
 46.1048 +     * found in the cache and the time-to-live periods of the instance and
 46.1049 +     * all of its parent instances have not expired, the instance is returned
 46.1050 +     * to the caller. Otherwise, this factory method proceeds with the
 46.1051 +     * loading process below.</li>
 46.1052 +     *
 46.1053 +     * <li>The {@link ResourceBundle.Control#getFormats(String)
 46.1054 +     * control.getFormats} method is called to get resource bundle formats
 46.1055 +     * to produce bundle or resource names. The strings
 46.1056 +     * <code>"java.class"</code> and <code>"java.properties"</code>
 46.1057 +     * designate class-based and {@linkplain PropertyResourceBundle
 46.1058 +     * property}-based resource bundles, respectively. Other strings
 46.1059 +     * starting with <code>"java."</code> are reserved for future extensions
 46.1060 +     * and must not be used for application-defined formats. Other strings
 46.1061 +     * designate application-defined formats.</li>
 46.1062 +     *
 46.1063 +     * <li>The {@link ResourceBundle.Control#getCandidateLocales(String,
 46.1064 +     * Locale) control.getCandidateLocales} method is called with the target
 46.1065 +     * locale to get a list of <em>candidate <code>Locale</code>s</em> for
 46.1066 +     * which resource bundles are searched.</li>
 46.1067 +     *
 46.1068 +     * <li>The {@link ResourceBundle.Control#newBundle(String, Locale,
 46.1069 +     * String, ClassLoader, boolean) control.newBundle} method is called to
 46.1070 +     * instantiate a <code>ResourceBundle</code> for the base bundle name, a
 46.1071 +     * candidate locale, and a format. (Refer to the note on the cache
 46.1072 +     * lookup below.) This step is iterated over all combinations of the
 46.1073 +     * candidate locales and formats until the <code>newBundle</code> method
 46.1074 +     * returns a <code>ResourceBundle</code> instance or the iteration has
 46.1075 +     * used up all the combinations. For example, if the candidate locales
 46.1076 +     * are <code>Locale("de", "DE")</code>, <code>Locale("de")</code> and
 46.1077 +     * <code>Locale("")</code> and the formats are <code>"java.class"</code>
 46.1078 +     * and <code>"java.properties"</code>, then the following is the
 46.1079 +     * sequence of locale-format combinations to be used to call
 46.1080 +     * <code>control.newBundle</code>.
 46.1081 +     *
 46.1082 +     * <table style="width: 50%; text-align: left; margin-left: 40px;"
 46.1083 +     *  border="0" cellpadding="2" cellspacing="2">
 46.1084 +     * <tbody><code>
 46.1085 +     * <tr>
 46.1086 +     * <td
 46.1087 +     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">Locale<br>
 46.1088 +     * </td>
 46.1089 +     * <td
 46.1090 +     * style="vertical-align: top; text-align: left; font-weight: bold; width: 50%;">format<br>
 46.1091 +     * </td>
 46.1092 +     * </tr>
 46.1093 +     * <tr>
 46.1094 +     * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")<br>
 46.1095 +     * </td>
 46.1096 +     * <td style="vertical-align: top; width: 50%;">java.class<br>
 46.1097 +     * </td>
 46.1098 +     * </tr>
 46.1099 +     * <tr>
 46.1100 +     * <td style="vertical-align: top; width: 50%;">Locale("de", "DE")</td>
 46.1101 +     * <td style="vertical-align: top; width: 50%;">java.properties<br>
 46.1102 +     * </td>
 46.1103 +     * </tr>
 46.1104 +     * <tr>
 46.1105 +     * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
 46.1106 +     * <td style="vertical-align: top; width: 50%;">java.class</td>
 46.1107 +     * </tr>
 46.1108 +     * <tr>
 46.1109 +     * <td style="vertical-align: top; width: 50%;">Locale("de")</td>
 46.1110 +     * <td style="vertical-align: top; width: 50%;">java.properties</td>
 46.1111 +     * </tr>
 46.1112 +     * <tr>
 46.1113 +     * <td style="vertical-align: top; width: 50%;">Locale("")<br>
 46.1114 +     * </td>
 46.1115 +     * <td style="vertical-align: top; width: 50%;">java.class</td>
 46.1116 +     * </tr>
 46.1117 +     * <tr>
 46.1118 +     * <td style="vertical-align: top; width: 50%;">Locale("")</td>
 46.1119 +     * <td style="vertical-align: top; width: 50%;">java.properties</td>
 46.1120 +     * </tr>
 46.1121 +     * </code></tbody>
 46.1122 +     * </table>
 46.1123 +     * </li>
 46.1124 +     *
 46.1125 +     * <li>If the previous step has found no resource bundle, proceed to
 46.1126 +     * Step 6. If a bundle has been found that is a base bundle (a bundle
 46.1127 +     * for <code>Locale("")</code>), and the candidate locale list only contained
 46.1128 +     * <code>Locale("")</code>, return the bundle to the caller. If a bundle
 46.1129 +     * has been found that is a base bundle, but the candidate locale list
 46.1130 +     * contained locales other than Locale(""), put the bundle on hold and
 46.1131 +     * proceed to Step 6. If a bundle has been found that is not a base
 46.1132 +     * bundle, proceed to Step 7.</li>
 46.1133 +     *
 46.1134 +     * <li>The {@link ResourceBundle.Control#getFallbackLocale(String,
 46.1135 +     * Locale) control.getFallbackLocale} method is called to get a fallback
 46.1136 +     * locale (alternative to the current target locale) to try further
 46.1137 +     * finding a resource bundle. If the method returns a non-null locale,
 46.1138 +     * it becomes the next target locale and the loading process starts over
 46.1139 +     * from Step 3. Otherwise, if a base bundle was found and put on hold in
 46.1140 +     * a previous Step 5, it is returned to the caller now. Otherwise, a
 46.1141 +     * MissingResourceException is thrown.</li>
 46.1142 +     *
 46.1143 +     * <li>At this point, we have found a resource bundle that's not the
 46.1144 +     * base bundle. If this bundle set its parent during its instantiation,
 46.1145 +     * it is returned to the caller. Otherwise, its <a
 46.1146 +     * href="./ResourceBundle.html#parent_chain">parent chain</a> is
 46.1147 +     * instantiated based on the list of candidate locales from which it was
 46.1148 +     * found. Finally, the bundle is returned to the caller.</li>
 46.1149 +     * </ol>
 46.1150 +     *
 46.1151 +     * <p>During the resource bundle loading process above, this factory
 46.1152 +     * method looks up the cache before calling the {@link
 46.1153 +     * Control#newBundle(String, Locale, String, ClassLoader, boolean)
 46.1154 +     * control.newBundle} method.  If the time-to-live period of the
 46.1155 +     * resource bundle found in the cache has expired, the factory method
 46.1156 +     * calls the {@link ResourceBundle.Control#needsReload(String, Locale,
 46.1157 +     * String, ClassLoader, ResourceBundle, long) control.needsReload}
 46.1158 +     * method to determine whether the resource bundle needs to be reloaded.
 46.1159 +     * If reloading is required, the factory method calls
 46.1160 +     * <code>control.newBundle</code> to reload the resource bundle.  If
 46.1161 +     * <code>control.newBundle</code> returns <code>null</code>, the factory
 46.1162 +     * method puts a dummy resource bundle in the cache as a mark of
 46.1163 +     * nonexistent resource bundles in order to avoid lookup overhead for
 46.1164 +     * subsequent requests. Such dummy resource bundles are under the same
 46.1165 +     * expiration control as specified by <code>control</code>.
 46.1166 +     *
 46.1167 +     * <p>All resource bundles loaded are cached by default. Refer to
 46.1168 +     * {@link Control#getTimeToLive(String,Locale)
 46.1169 +     * control.getTimeToLive} for details.
 46.1170 +     *
 46.1171 +     * <p>The following is an example of the bundle loading process with the
 46.1172 +     * default <code>ResourceBundle.Control</code> implementation.
 46.1173 +     *
 46.1174 +     * <p>Conditions:
 46.1175 +     * <ul>
 46.1176 +     * <li>Base bundle name: <code>foo.bar.Messages</code>
 46.1177 +     * <li>Requested <code>Locale</code>: {@link Locale#ITALY}</li>
 46.1178 +     * <li>Default <code>Locale</code>: {@link Locale#FRENCH}</li>
 46.1179 +     * <li>Available resource bundles:
 46.1180 +     * <code>foo/bar/Messages_fr.properties</code> and
 46.1181 +     * <code>foo/bar/Messages.properties</code></li>
 46.1182 +     * </ul>
 46.1183 +     *
 46.1184 +     * <p>First, <code>getBundle</code> tries loading a resource bundle in
 46.1185 +     * the following sequence.
 46.1186 +     *
 46.1187 +     * <ul>
 46.1188 +     * <li>class <code>foo.bar.Messages_it_IT</code>
 46.1189 +     * <li>file <code>foo/bar/Messages_it_IT.properties</code>
 46.1190 +     * <li>class <code>foo.bar.Messages_it</code></li>
 46.1191 +     * <li>file <code>foo/bar/Messages_it.properties</code></li>
 46.1192 +     * <li>class <code>foo.bar.Messages</code></li>
 46.1193 +     * <li>file <code>foo/bar/Messages.properties</code></li>
 46.1194 +     * </ul>
 46.1195 +     *
 46.1196 +     * <p>At this point, <code>getBundle</code> finds
 46.1197 +     * <code>foo/bar/Messages.properties</code>, which is put on hold
 46.1198 +     * because it's the base bundle.  <code>getBundle</code> calls {@link
 46.1199 +     * Control#getFallbackLocale(String, Locale)
 46.1200 +     * control.getFallbackLocale("foo.bar.Messages", Locale.ITALY)} which
 46.1201 +     * returns <code>Locale.FRENCH</code>. Next, <code>getBundle</code>
 46.1202 +     * tries loading a bundle in the following sequence.
 46.1203 +     *
 46.1204 +     * <ul>
 46.1205 +     * <li>class <code>foo.bar.Messages_fr</code></li>
 46.1206 +     * <li>file <code>foo/bar/Messages_fr.properties</code></li>
 46.1207 +     * <li>class <code>foo.bar.Messages</code></li>
 46.1208 +     * <li>file <code>foo/bar/Messages.properties</code></li>
 46.1209 +     * </ul>
 46.1210 +     *
 46.1211 +     * <p><code>getBundle</code> finds
 46.1212 +     * <code>foo/bar/Messages_fr.properties</code> and creates a
 46.1213 +     * <code>ResourceBundle</code> instance. Then, <code>getBundle</code>
 46.1214 +     * sets up its parent chain from the list of the candiate locales.  Only
 46.1215 +     * <code>foo/bar/Messages.properties</code> is found in the list and
 46.1216 +     * <code>getBundle</code> creates a <code>ResourceBundle</code> instance
 46.1217 +     * that becomes the parent of the instance for
 46.1218 +     * <code>foo/bar/Messages_fr.properties</code>.
 46.1219 +     *
 46.1220 +     * @param baseName
 46.1221 +     *        the base name of the resource bundle, a fully qualified
 46.1222 +     *        class name
 46.1223 +     * @param targetLocale
 46.1224 +     *        the locale for which a resource bundle is desired
 46.1225 +     * @param loader
 46.1226 +     *        the class loader from which to load the resource bundle
 46.1227 +     * @param control
 46.1228 +     *        the control which gives information for the resource
 46.1229 +     *        bundle loading process
 46.1230 +     * @return a resource bundle for the given base name and locale
 46.1231 +     * @exception NullPointerException
 46.1232 +     *        if <code>baseName</code>, <code>targetLocale</code>,
 46.1233 +     *        <code>loader</code>, or <code>control</code> is
 46.1234 +     *        <code>null</code>
 46.1235 +     * @exception MissingResourceException
 46.1236 +     *        if no resource bundle for the specified base name can be found
 46.1237 +     * @exception IllegalArgumentException
 46.1238 +     *        if the given <code>control</code> doesn't perform properly
 46.1239 +     *        (e.g., <code>control.getCandidateLocales</code> returns null.)
 46.1240 +     *        Note that validation of <code>control</code> is performed as
 46.1241 +     *        needed.
 46.1242 +     * @since 1.6
 46.1243 +     */
 46.1244 +    public static ResourceBundle getBundle(String baseName, Locale targetLocale,
 46.1245 +                                           ClassLoader loader, Control control) {
 46.1246 +        if (loader == null || control == null) {
 46.1247 +            throw new NullPointerException();
 46.1248 +        }
 46.1249 +        return getBundleImpl(baseName, targetLocale, loader, control);
 46.1250 +    }
 46.1251 +
 46.1252 +    private static ResourceBundle getBundleImpl(String baseName, Locale locale,
 46.1253 +                                                ClassLoader loader, Control control) {
 46.1254 +        if (locale == null || control == null) {
 46.1255 +            throw new NullPointerException();
 46.1256 +        }
 46.1257 +
 46.1258 +        // We create a CacheKey here for use by this call. The base
 46.1259 +        // name and loader will never change during the bundle loading
 46.1260 +        // process. We have to make sure that the locale is set before
 46.1261 +        // using it as a cache key.
 46.1262 +        CacheKey cacheKey = new CacheKey(baseName, locale, loader);
 46.1263 +        ResourceBundle bundle = null;
 46.1264 +
 46.1265 +        // Quick lookup of the cache.
 46.1266 +        BundleReference bundleRef = cacheList.get(cacheKey);
 46.1267 +        if (bundleRef != null) {
 46.1268 +            bundle = bundleRef.get();
 46.1269 +            bundleRef = null;
 46.1270 +        }
 46.1271 +
 46.1272 +        // If this bundle and all of its parents are valid (not expired),
 46.1273 +        // then return this bundle. If any of the bundles is expired, we
 46.1274 +        // don't call control.needsReload here but instead drop into the
 46.1275 +        // complete loading process below.
 46.1276 +        if (isValidBundle(bundle) && hasValidParentChain(bundle)) {
 46.1277 +            return bundle;
 46.1278 +        }
 46.1279 +
 46.1280 +        // No valid bundle was found in the cache, so we need to load the
 46.1281 +        // resource bundle and its parents.
 46.1282 +
 46.1283 +        boolean isKnownControl = (control == Control.INSTANCE) ||
 46.1284 +                                   (control instanceof SingleFormatControl);
 46.1285 +        List<String> formats = control.getFormats(baseName);
 46.1286 +        if (!isKnownControl && !checkList(formats)) {
 46.1287 +            throw new IllegalArgumentException("Invalid Control: getFormats");
 46.1288 +        }
 46.1289 +
 46.1290 +        ResourceBundle baseBundle = null;
 46.1291 +        for (Locale targetLocale = locale;
 46.1292 +             targetLocale != null;
 46.1293 +             targetLocale = control.getFallbackLocale(baseName, targetLocale)) {
 46.1294 +            List<Locale> candidateLocales = control.getCandidateLocales(baseName, targetLocale);
 46.1295 +            if (!isKnownControl && !checkList(candidateLocales)) {
 46.1296 +                throw new IllegalArgumentException("Invalid Control: getCandidateLocales");
 46.1297 +            }
 46.1298 +
 46.1299 +            bundle = findBundle(cacheKey, candidateLocales, formats, 0, control, baseBundle);
 46.1300 +
 46.1301 +            // If the loaded bundle is the base bundle and exactly for the
 46.1302 +            // requested locale or the only candidate locale, then take the
 46.1303 +            // bundle as the resulting one. If the loaded bundle is the base
 46.1304 +            // bundle, it's put on hold until we finish processing all
 46.1305 +            // fallback locales.
 46.1306 +            if (isValidBundle(bundle)) {
 46.1307 +                boolean isBaseBundle = Locale.ROOT.equals(bundle.locale);
 46.1308 +                if (!isBaseBundle || bundle.locale.equals(locale)
 46.1309 +                    || (candidateLocales.size() == 1
 46.1310 +                        && bundle.locale.equals(candidateLocales.get(0)))) {
 46.1311 +                    break;
 46.1312 +                }
 46.1313 +
 46.1314 +                // If the base bundle has been loaded, keep the reference in
 46.1315 +                // baseBundle so that we can avoid any redundant loading in case
 46.1316 +                // the control specify not to cache bundles.
 46.1317 +                if (isBaseBundle && baseBundle == null) {
 46.1318 +                    baseBundle = bundle;
 46.1319 +                }
 46.1320 +            }
 46.1321 +        }
 46.1322 +
 46.1323 +        if (bundle == null) {
 46.1324 +            if (baseBundle == null) {
 46.1325 +                throwMissingResourceException(baseName, locale, cacheKey.getCause());
 46.1326 +            }
 46.1327 +            bundle = baseBundle;
 46.1328 +        }
 46.1329 +
 46.1330 +        return bundle;
 46.1331 +    }
 46.1332 +
 46.1333 +    /**
 46.1334 +     * Checks if the given <code>List</code> is not null, not empty,
 46.1335 +     * not having null in its elements.
 46.1336 +     */
 46.1337 +    private static final boolean checkList(List a) {
 46.1338 +        boolean valid = (a != null && a.size() != 0);
 46.1339 +        if (valid) {
 46.1340 +            int size = a.size();
 46.1341 +            for (int i = 0; valid && i < size; i++) {
 46.1342 +                valid = (a.get(i) != null);
 46.1343 +            }
 46.1344 +        }
 46.1345 +        return valid;
 46.1346 +    }
 46.1347 +
 46.1348 +    private static final ResourceBundle findBundle(CacheKey cacheKey,
 46.1349 +                                                   List<Locale> candidateLocales,
 46.1350 +                                                   List<String> formats,
 46.1351 +                                                   int index,
 46.1352 +                                                   Control control,
 46.1353 +                                                   ResourceBundle baseBundle) {
 46.1354 +        Locale targetLocale = candidateLocales.get(index);
 46.1355 +        ResourceBundle parent = null;
 46.1356 +        if (index != candidateLocales.size() - 1) {
 46.1357 +            parent = findBundle(cacheKey, candidateLocales, formats, index + 1,
 46.1358 +                                control, baseBundle);
 46.1359 +        } else if (baseBundle != null && Locale.ROOT.equals(targetLocale)) {
 46.1360 +            return baseBundle;
 46.1361 +        }
 46.1362 +
 46.1363 +        // Before we do the real loading work, see whether we need to
 46.1364 +        // do some housekeeping: If references to class loaders or
 46.1365 +        // resource bundles have been nulled out, remove all related
 46.1366 +        // information from the cache.
 46.1367 +        Object ref;
 46.1368 +        while ((ref = referenceQueue.poll()) != null) {
 46.1369 +            cacheList.remove(((CacheKeyReference)ref).getCacheKey());
 46.1370 +        }
 46.1371 +
 46.1372 +        // flag indicating the resource bundle has expired in the cache
 46.1373 +        boolean expiredBundle = false;
 46.1374 +
 46.1375 +        // First, look up the cache to see if it's in the cache, without
 46.1376 +        // attempting to load bundle.
 46.1377 +        cacheKey.setLocale(targetLocale);
 46.1378 +        ResourceBundle bundle = findBundleInCache(cacheKey, control);
 46.1379 +        if (isValidBundle(bundle)) {
 46.1380 +            expiredBundle = bundle.expired;
 46.1381 +            if (!expiredBundle) {
 46.1382 +                // If its parent is the one asked for by the candidate
 46.1383 +                // locales (the runtime lookup path), we can take the cached
 46.1384 +                // one. (If it's not identical, then we'd have to check the
 46.1385 +                // parent's parents to be consistent with what's been
 46.1386 +                // requested.)
 46.1387 +                if (bundle.parent == parent) {
 46.1388 +                    return bundle;
 46.1389 +                }
 46.1390 +                // Otherwise, remove the cached one since we can't keep
 46.1391 +                // the same bundles having different parents.
 46.1392 +                BundleReference bundleRef = cacheList.get(cacheKey);
 46.1393 +                if (bundleRef != null && bundleRef.get() == bundle) {
 46.1394 +                    cacheList.remove(cacheKey, bundleRef);
 46.1395 +                }
 46.1396 +            }
 46.1397 +        }
 46.1398 +
 46.1399 +        if (bundle != NONEXISTENT_BUNDLE) {
 46.1400 +            CacheKey constKey = (CacheKey) cacheKey.clone();
 46.1401 +
 46.1402 +            try {
 46.1403 +                bundle = loadBundle(cacheKey, formats, control, expiredBundle);
 46.1404 +                if (bundle != null) {
 46.1405 +                    if (bundle.parent == null) {
 46.1406 +                        bundle.setParent(parent);
 46.1407 +                    }
 46.1408 +                    bundle.locale = targetLocale;
 46.1409 +                    bundle = putBundleInCache(cacheKey, bundle, control);
 46.1410 +                    return bundle;
 46.1411 +                }
 46.1412 +
 46.1413 +                // Put NONEXISTENT_BUNDLE in the cache as a mark that there's no bundle
 46.1414 +                // instance for the locale.
 46.1415 +                putBundleInCache(cacheKey, NONEXISTENT_BUNDLE, control);
 46.1416 +            } finally {
 46.1417 +                if (constKey.getCause() instanceof InterruptedException) {
 46.1418 +                    Thread.currentThread().interrupt();
 46.1419 +                }
 46.1420 +            }
 46.1421 +        }
 46.1422 +        return parent;
 46.1423 +    }
 46.1424 +
 46.1425 +    private static final ResourceBundle loadBundle(CacheKey cacheKey,
 46.1426 +                                                   List<String> formats,
 46.1427 +                                                   Control control,
 46.1428 +                                                   boolean reload) {
 46.1429 +
 46.1430 +        // Here we actually load the bundle in the order of formats
 46.1431 +        // specified by the getFormats() value.
 46.1432 +        Locale targetLocale = cacheKey.getLocale();
 46.1433 +
 46.1434 +        ResourceBundle bundle = null;
 46.1435 +        int size = formats.size();
 46.1436 +        for (int i = 0; i < size; i++) {
 46.1437 +            String format = formats.get(i);
 46.1438 +            try {
 46.1439 +                bundle = control.newBundle(cacheKey.getName(), targetLocale, format,
 46.1440 +                                           cacheKey.getLoader(), reload);
 46.1441 +            } catch (LinkageError error) {
 46.1442 +                // We need to handle the LinkageError case due to
 46.1443 +                // inconsistent case-sensitivity in ClassLoader.
 46.1444 +                // See 6572242 for details.
 46.1445 +                cacheKey.setCause(error);
 46.1446 +            } catch (Exception cause) {
 46.1447 +                cacheKey.setCause(cause);
 46.1448 +            }
 46.1449 +            if (bundle != null) {
 46.1450 +                // Set the format in the cache key so that it can be
 46.1451 +                // used when calling needsReload later.
 46.1452 +                cacheKey.setFormat(format);
 46.1453 +                bundle.name = cacheKey.getName();
 46.1454 +                bundle.locale = targetLocale;
 46.1455 +                // Bundle provider might reuse instances. So we should make
 46.1456 +                // sure to clear the expired flag here.
 46.1457 +                bundle.expired = false;
 46.1458 +                break;
 46.1459 +            }
 46.1460 +        }
 46.1461 +
 46.1462 +        return bundle;
 46.1463 +    }
 46.1464 +
 46.1465 +    private static final boolean isValidBundle(ResourceBundle bundle) {
 46.1466 +        return bundle != null && bundle != NONEXISTENT_BUNDLE;
 46.1467 +    }
 46.1468 +
 46.1469 +    /**
 46.1470 +     * Determines whether any of resource bundles in the parent chain,
 46.1471 +     * including the leaf, have expired.
 46.1472 +     */
 46.1473 +    private static final boolean hasValidParentChain(ResourceBundle bundle) {
 46.1474 +        long now = System.currentTimeMillis();
 46.1475 +        while (bundle != null) {
 46.1476 +            if (bundle.expired) {
 46.1477 +                return false;
 46.1478 +            }
 46.1479 +            CacheKey key = bundle.cacheKey;
 46.1480 +            if (key != null) {
 46.1481 +                long expirationTime = key.expirationTime;
 46.1482 +                if (expirationTime >= 0 && expirationTime <= now) {
 46.1483 +                    return false;
 46.1484 +                }
 46.1485 +            }
 46.1486 +            bundle = bundle.parent;
 46.1487 +        }
 46.1488 +        return true;
 46.1489 +    }
 46.1490 +
 46.1491 +    /**
 46.1492 +     * Throw a MissingResourceException with proper message
 46.1493 +     */
 46.1494 +    private static final void throwMissingResourceException(String baseName,
 46.1495 +                                                            Locale locale,
 46.1496 +                                                            Throwable cause) {
 46.1497 +        // If the cause is a MissingResourceException, avoid creating
 46.1498 +        // a long chain. (6355009)
 46.1499 +        if (cause instanceof MissingResourceException) {
 46.1500 +            cause = null;
 46.1501 +        }
 46.1502 +        throw new MissingResourceException("Can't find bundle for base name "
 46.1503 +                                           + baseName + ", locale " + locale,
 46.1504 +                                           baseName + "_" + locale, // className
 46.1505 +                                           "",                      // key
 46.1506 +                                           cause);
 46.1507 +    }
 46.1508 +
 46.1509 +    /**
 46.1510 +     * Finds a bundle in the cache. Any expired bundles are marked as
 46.1511 +     * `expired' and removed from the cache upon return.
 46.1512 +     *
 46.1513 +     * @param cacheKey the key to look up the cache
 46.1514 +     * @param control the Control to be used for the expiration control
 46.1515 +     * @return the cached bundle, or null if the bundle is not found in the
 46.1516 +     * cache or its parent has expired. <code>bundle.expire</code> is true
 46.1517 +     * upon return if the bundle in the cache has expired.
 46.1518 +     */
 46.1519 +    private static final ResourceBundle findBundleInCache(CacheKey cacheKey,
 46.1520 +                                                          Control control) {
 46.1521 +        BundleReference bundleRef = cacheList.get(cacheKey);
 46.1522 +        if (bundleRef == null) {
 46.1523 +            return null;
 46.1524 +        }
 46.1525 +        ResourceBundle bundle = bundleRef.get();
 46.1526 +        if (bundle == null) {
 46.1527 +            return null;
 46.1528 +        }
 46.1529 +        ResourceBundle p = bundle.parent;
 46.1530 +        assert p != NONEXISTENT_BUNDLE;
 46.1531 +        // If the parent has expired, then this one must also expire. We
 46.1532 +        // check only the immediate parent because the actual loading is
 46.1533 +        // done from the root (base) to leaf (child) and the purpose of
 46.1534 +        // checking is to propagate expiration towards the leaf. For
 46.1535 +        // example, if the requested locale is ja_JP_JP and there are
 46.1536 +        // bundles for all of the candidates in the cache, we have a list,
 46.1537 +        //
 46.1538 +        // base <- ja <- ja_JP <- ja_JP_JP
 46.1539 +        //
 46.1540 +        // If ja has expired, then it will reload ja and the list becomes a
 46.1541 +        // tree.
 46.1542 +        //
 46.1543 +        // base <- ja (new)
 46.1544 +        //  "   <- ja (expired) <- ja_JP <- ja_JP_JP
 46.1545 +        //
 46.1546 +        // When looking up ja_JP in the cache, it finds ja_JP in the cache
 46.1547 +        // which references to the expired ja. Then, ja_JP is marked as
 46.1548 +        // expired and removed from the cache. This will be propagated to
 46.1549 +        // ja_JP_JP.
 46.1550 +        //
 46.1551 +        // Now, it's possible, for example, that while loading new ja_JP,
 46.1552 +        // someone else has started loading the same bundle and finds the
 46.1553 +        // base bundle has expired. Then, what we get from the first
 46.1554 +        // getBundle call includes the expired base bundle. However, if
 46.1555 +        // someone else didn't start its loading, we wouldn't know if the
 46.1556 +        // base bundle has expired at the end of the loading process. The
 46.1557 +        // expiration control doesn't guarantee that the returned bundle and
 46.1558 +        // its parents haven't expired.
 46.1559 +        //
 46.1560 +        // We could check the entire parent chain to see if there's any in
 46.1561 +        // the chain that has expired. But this process may never end. An
 46.1562 +        // extreme case would be that getTimeToLive returns 0 and
 46.1563 +        // needsReload always returns true.
 46.1564 +        if (p != null && p.expired) {
 46.1565 +            assert bundle != NONEXISTENT_BUNDLE;
 46.1566 +            bundle.expired = true;
 46.1567 +            bundle.cacheKey = null;
 46.1568 +            cacheList.remove(cacheKey, bundleRef);
 46.1569 +            bundle = null;
 46.1570 +        } else {
 46.1571 +            CacheKey key = bundleRef.getCacheKey();
 46.1572 +            long expirationTime = key.expirationTime;
 46.1573 +            if (!bundle.expired && expirationTime >= 0 &&
 46.1574 +                expirationTime <= System.currentTimeMillis()) {
 46.1575 +                // its TTL period has expired.
 46.1576 +                if (bundle != NONEXISTENT_BUNDLE) {
 46.1577 +                    // Synchronize here to call needsReload to avoid
 46.1578 +                    // redundant concurrent calls for the same bundle.
 46.1579 +                    synchronized (bundle) {
 46.1580 +                        expirationTime = key.expirationTime;
 46.1581 +                        if (!bundle.expired && expirationTime >= 0 &&
 46.1582 +                            expirationTime <= System.currentTimeMillis()) {
 46.1583 +                            try {
 46.1584 +                                bundle.expired = control.needsReload(key.getName(),
 46.1585 +                                                                     key.getLocale(),
 46.1586 +                                                                     key.getFormat(),
 46.1587 +                                                                     key.getLoader(),
 46.1588 +                                                                     bundle,
 46.1589 +                                                                     key.loadTime);
 46.1590 +                            } catch (Exception e) {
 46.1591 +                                cacheKey.setCause(e);
 46.1592 +                            }
 46.1593 +                            if (bundle.expired) {
 46.1594 +                                // If the bundle needs to be reloaded, then
 46.1595 +                                // remove the bundle from the cache, but
 46.1596 +                                // return the bundle with the expired flag
 46.1597 +                                // on.
 46.1598 +                                bundle.cacheKey = null;
 46.1599 +                                cacheList.remove(cacheKey, bundleRef);
 46.1600 +                            } else {
 46.1601 +                                // Update the expiration control info. and reuse
 46.1602 +                                // the same bundle instance
 46.1603 +                                setExpirationTime(key, control);
 46.1604 +                            }
 46.1605 +                        }
 46.1606 +                    }
 46.1607 +                } else {
 46.1608 +                    // We just remove NONEXISTENT_BUNDLE from the cache.
 46.1609 +                    cacheList.remove(cacheKey, bundleRef);
 46.1610 +                    bundle = null;
 46.1611 +                }
 46.1612 +            }
 46.1613 +        }
 46.1614 +        return bundle;
 46.1615 +    }
 46.1616 +
 46.1617 +    /**
 46.1618 +     * Put a new bundle in the cache.
 46.1619 +     *
 46.1620 +     * @param cacheKey the key for the resource bundle
 46.1621 +     * @param bundle the resource bundle to be put in the cache
 46.1622 +     * @return the ResourceBundle for the cacheKey; if someone has put
 46.1623 +     * the bundle before this call, the one found in the cache is
 46.1624 +     * returned.
 46.1625 +     */
 46.1626 +    private static final ResourceBundle putBundleInCache(CacheKey cacheKey,
 46.1627 +                                                         ResourceBundle bundle,
 46.1628 +                                                         Control control) {
 46.1629 +        setExpirationTime(cacheKey, control);
 46.1630 +        if (cacheKey.expirationTime != Control.TTL_DONT_CACHE) {
 46.1631 +            CacheKey key = (CacheKey) cacheKey.clone();
 46.1632 +            BundleReference bundleRef = new BundleReference(bundle, referenceQueue, key);
 46.1633 +            bundle.cacheKey = key;
 46.1634 +
 46.1635 +            // Put the bundle in the cache if it's not been in the cache.
 46.1636 +            BundleReference result = cacheList.putIfAbsent(key, bundleRef);
 46.1637 +
 46.1638 +            // If someone else has put the same bundle in the cache before
 46.1639 +            // us and it has not expired, we should use the one in the cache.
 46.1640 +            if (result != null) {
 46.1641 +                ResourceBundle rb = result.get();
 46.1642 +                if (rb != null && !rb.expired) {
 46.1643 +                    // Clear the back link to the cache key
 46.1644 +                    bundle.cacheKey = null;
 46.1645 +                    bundle = rb;
 46.1646 +                    // Clear the reference in the BundleReference so that
 46.1647 +                    // it won't be enqueued.
 46.1648 +                    bundleRef.clear();
 46.1649 +                } else {
 46.1650 +                    // Replace the invalid (garbage collected or expired)
 46.1651 +                    // instance with the valid one.
 46.1652 +                    cacheList.put(key, bundleRef);
 46.1653 +                }
 46.1654 +            }
 46.1655 +        }
 46.1656 +        return bundle;
 46.1657 +    }
 46.1658 +
 46.1659 +    private static final void setExpirationTime(CacheKey cacheKey, Control control) {
 46.1660 +        long ttl = control.getTimeToLive(cacheKey.getName(),
 46.1661 +                                         cacheKey.getLocale());
 46.1662 +        if (ttl >= 0) {
 46.1663 +            // If any expiration time is specified, set the time to be
 46.1664 +            // expired in the cache.
 46.1665 +            long now = System.currentTimeMillis();
 46.1666 +            cacheKey.loadTime = now;
 46.1667 +            cacheKey.expirationTime = now + ttl;
 46.1668 +        } else if (ttl >= Control.TTL_NO_EXPIRATION_CONTROL) {
 46.1669 +            cacheKey.expirationTime = ttl;
 46.1670 +        } else {
 46.1671 +            throw new IllegalArgumentException("Invalid Control: TTL=" + ttl);
 46.1672 +        }
 46.1673 +    }
 46.1674 +
 46.1675 +    /**
 46.1676 +     * Removes all resource bundles from the cache that have been loaded
 46.1677 +     * using the caller's class loader.
 46.1678 +     *
 46.1679 +     * @since 1.6
 46.1680 +     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
 46.1681 +     */
 46.1682 +    public static final void clearCache() {
 46.1683 +        clearCache(getLoader());
 46.1684 +    }
 46.1685 +
 46.1686 +    /**
 46.1687 +     * Removes all resource bundles from the cache that have been loaded
 46.1688 +     * using the given class loader.
 46.1689 +     *
 46.1690 +     * @param loader the class loader
 46.1691 +     * @exception NullPointerException if <code>loader</code> is null
 46.1692 +     * @since 1.6
 46.1693 +     * @see ResourceBundle.Control#getTimeToLive(String,Locale)
 46.1694 +     */
 46.1695 +    public static final void clearCache(ClassLoader loader) {
 46.1696 +        if (loader == null) {
 46.1697 +            throw new NullPointerException();
 46.1698 +        }
 46.1699 +        Set<CacheKey> set = cacheList.keySet();
 46.1700 +        for (CacheKey key : set) {
 46.1701 +            if (key.getLoader() == loader) {
 46.1702 +                set.remove(key);
 46.1703 +            }
 46.1704 +        }
 46.1705 +    }
 46.1706 +
 46.1707 +    /**
 46.1708 +     * Gets an object for the given key from this resource bundle.
 46.1709 +     * Returns null if this resource bundle does not contain an
 46.1710 +     * object for the given key.
 46.1711 +     *
 46.1712 +     * @param key the key for the desired object
 46.1713 +     * @exception NullPointerException if <code>key</code> is <code>null</code>
 46.1714 +     * @return the object for the given key, or null
 46.1715 +     */
 46.1716 +    protected abstract Object handleGetObject(String key);
 46.1717 +
 46.1718 +    /**
 46.1719 +     * Returns an enumeration of the keys.
 46.1720 +     *
 46.1721 +     * @return an <code>Enumeration</code> of the keys contained in
 46.1722 +     *         this <code>ResourceBundle</code> and its parent bundles.
 46.1723 +     */
 46.1724 +    public abstract Enumeration<String> getKeys();
 46.1725 +
 46.1726 +    /**
 46.1727 +     * Determines whether the given <code>key</code> is contained in
 46.1728 +     * this <code>ResourceBundle</code> or its parent bundles.
 46.1729 +     *
 46.1730 +     * @param key
 46.1731 +     *        the resource <code>key</code>
 46.1732 +     * @return <code>true</code> if the given <code>key</code> is
 46.1733 +     *        contained in this <code>ResourceBundle</code> or its
 46.1734 +     *        parent bundles; <code>false</code> otherwise.
 46.1735 +     * @exception NullPointerException
 46.1736 +     *         if <code>key</code> is <code>null</code>
 46.1737 +     * @since 1.6
 46.1738 +     */
 46.1739 +    public boolean containsKey(String key) {
 46.1740 +        if (key == null) {
 46.1741 +            throw new NullPointerException();
 46.1742 +        }
 46.1743 +        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
 46.1744 +            if (rb.handleKeySet().contains(key)) {
 46.1745 +                return true;
 46.1746 +            }
 46.1747 +        }
 46.1748 +        return false;
 46.1749 +    }
 46.1750 +
 46.1751 +    /**
 46.1752 +     * Returns a <code>Set</code> of all keys contained in this
 46.1753 +     * <code>ResourceBundle</code> and its parent bundles.
 46.1754 +     *
 46.1755 +     * @return a <code>Set</code> of all keys contained in this
 46.1756 +     *         <code>ResourceBundle</code> and its parent bundles.
 46.1757 +     * @since 1.6
 46.1758 +     */
 46.1759 +    public Set<String> keySet() {
 46.1760 +        Set<String> keys = new HashSet<>();
 46.1761 +        for (ResourceBundle rb = this; rb != null; rb = rb.parent) {
 46.1762 +            keys.addAll(rb.handleKeySet());
 46.1763 +        }
 46.1764 +        return keys;
 46.1765 +    }
 46.1766 +
 46.1767 +    /**
 46.1768 +     * Returns a <code>Set</code> of the keys contained <em>only</em>
 46.1769 +     * in this <code>ResourceBundle</code>.
 46.1770 +     *
 46.1771 +     * <p>The default implementation returns a <code>Set</code> of the
 46.1772 +     * keys returned by the {@link #getKeys() getKeys} method except
 46.1773 +     * for the ones for which the {@link #handleGetObject(String)
 46.1774 +     * handleGetObject} method returns <code>null</code>. Once the
 46.1775 +     * <code>Set</code> has been created, the value is kept in this
 46.1776 +     * <code>ResourceBundle</code> in order to avoid producing the
 46.1777 +     * same <code>Set</code> in subsequent calls. Subclasses can
 46.1778 +     * override this method for faster handling.
 46.1779 +     *
 46.1780 +     * @return a <code>Set</code> of the keys contained only in this
 46.1781 +     *        <code>ResourceBundle</code>
 46.1782 +     * @since 1.6
 46.1783 +     */
 46.1784 +    protected Set<String> handleKeySet() {
 46.1785 +        if (keySet == null) {
 46.1786 +            synchronized (this) {
 46.1787 +                if (keySet == null) {
 46.1788 +                    Set<String> keys = new HashSet<>();
 46.1789 +                    Enumeration<String> enumKeys = getKeys();
 46.1790 +                    while (enumKeys.hasMoreElements()) {
 46.1791 +                        String key = enumKeys.nextElement();
 46.1792 +                        if (handleGetObject(key) != null) {
 46.1793 +                            keys.add(key);
 46.1794 +                        }
 46.1795 +                    }
 46.1796 +                    keySet = keys;
 46.1797 +                }
 46.1798 +            }
 46.1799 +        }
 46.1800 +        return keySet;
 46.1801 +    }
 46.1802 +
 46.1803 +
 46.1804 +
 46.1805 +    /**
 46.1806 +     * <code>ResourceBundle.Control</code> defines a set of callback methods
 46.1807 +     * that are invoked by the {@link ResourceBundle#getBundle(String,
 46.1808 +     * Locale, ClassLoader, Control) ResourceBundle.getBundle} factory
 46.1809 +     * methods during the bundle loading process. In other words, a
 46.1810 +     * <code>ResourceBundle.Control</code> collaborates with the factory
 46.1811 +     * methods for loading resource bundles. The default implementation of
 46.1812 +     * the callback methods provides the information necessary for the
 46.1813 +     * factory methods to perform the <a
 46.1814 +     * href="./ResourceBundle.html#default_behavior">default behavior</a>.
 46.1815 +     *
 46.1816 +     * <p>In addition to the callback methods, the {@link
 46.1817 +     * #toBundleName(String, Locale) toBundleName} and {@link
 46.1818 +     * #toResourceName(String, String) toResourceName} methods are defined
 46.1819 +     * primarily for convenience in implementing the callback
 46.1820 +     * methods. However, the <code>toBundleName</code> method could be
 46.1821 +     * overridden to provide different conventions in the organization and
 46.1822 +     * packaging of localized resources.  The <code>toResourceName</code>
 46.1823 +     * method is <code>final</code> to avoid use of wrong resource and class
 46.1824 +     * name separators.
 46.1825 +     *
 46.1826 +     * <p>Two factory methods, {@link #getControl(List)} and {@link
 46.1827 +     * #getNoFallbackControl(List)}, provide
 46.1828 +     * <code>ResourceBundle.Control</code> instances that implement common
 46.1829 +     * variations of the default bundle loading process.
 46.1830 +     *
 46.1831 +     * <p>The formats returned by the {@link Control#getFormats(String)
 46.1832 +     * getFormats} method and candidate locales returned by the {@link
 46.1833 +     * ResourceBundle.Control#getCandidateLocales(String, Locale)
 46.1834 +     * getCandidateLocales} method must be consistent in all
 46.1835 +     * <code>ResourceBundle.getBundle</code> invocations for the same base
 46.1836 +     * bundle. Otherwise, the <code>ResourceBundle.getBundle</code> methods
 46.1837 +     * may return unintended bundles. For example, if only
 46.1838 +     * <code>"java.class"</code> is returned by the <code>getFormats</code>
 46.1839 +     * method for the first call to <code>ResourceBundle.getBundle</code>
 46.1840 +     * and only <code>"java.properties"</code> for the second call, then the
 46.1841 +     * second call will return the class-based one that has been cached
 46.1842 +     * during the first call.
 46.1843 +     *
 46.1844 +     * <p>A <code>ResourceBundle.Control</code> instance must be thread-safe
 46.1845 +     * if it's simultaneously used by multiple threads.
 46.1846 +     * <code>ResourceBundle.getBundle</code> does not synchronize to call
 46.1847 +     * the <code>ResourceBundle.Control</code> methods. The default
 46.1848 +     * implementations of the methods are thread-safe.
 46.1849 +     *
 46.1850 +     * <p>Applications can specify <code>ResourceBundle.Control</code>
 46.1851 +     * instances returned by the <code>getControl</code> factory methods or
 46.1852 +     * created from a subclass of <code>ResourceBundle.Control</code> to
 46.1853 +     * customize the bundle loading process. The following are examples of
 46.1854 +     * changing the default bundle loading process.
 46.1855 +     *
 46.1856 +     * <p><b>Example 1</b>
 46.1857 +     *
 46.1858 +     * <p>The following code lets <code>ResourceBundle.getBundle</code> look
 46.1859 +     * up only properties-based resources.
 46.1860 +     *
 46.1861 +     * <pre>
 46.1862 +     * import java.util.*;
 46.1863 +     * import static java.util.ResourceBundle.Control.*;
 46.1864 +     * ...
 46.1865 +     * ResourceBundle bundle =
 46.1866 +     *   ResourceBundle.getBundle("MyResources", new Locale("fr", "CH"),
 46.1867 +     *                            ResourceBundle.Control.getControl(FORMAT_PROPERTIES));
 46.1868 +     * </pre>
 46.1869 +     *
 46.1870 +     * Given the resource bundles in the <a
 46.1871 +     * href="./ResourceBundle.html#default_behavior_example">example</a> in
 46.1872 +     * the <code>ResourceBundle.getBundle</code> description, this
 46.1873 +     * <code>ResourceBundle.getBundle</code> call loads
 46.1874 +     * <code>MyResources_fr_CH.properties</code> whose parent is
 46.1875 +     * <code>MyResources_fr.properties</code> whose parent is
 46.1876 +     * <code>MyResources.properties</code>. (<code>MyResources_fr_CH.properties</code>
 46.1877 +     * is not hidden, but <code>MyResources_fr_CH.class</code> is.)
 46.1878 +     *
 46.1879 +     * <p><b>Example 2</b>
 46.1880 +     *
 46.1881 +     * <p>The following is an example of loading XML-based bundles
 46.1882 +     * using {@link Properties#loadFromXML(java.io.InputStream)
 46.1883 +     * Properties.loadFromXML}.
 46.1884 +     *
 46.1885 +     * <pre>
 46.1886 +     * ResourceBundle rb = ResourceBundle.getBundle("Messages",
 46.1887 +     *     new ResourceBundle.Control() {
 46.1888 +     *         public List&lt;String&gt; getFormats(String baseName) {
 46.1889 +     *             if (baseName == null)
 46.1890 +     *                 throw new NullPointerException();
 46.1891 +     *             return Arrays.asList("xml");
 46.1892 +     *         }
 46.1893 +     *         public ResourceBundle newBundle(String baseName,
 46.1894 +     *                                         Locale locale,
 46.1895 +     *                                         String format,
 46.1896 +     *                                         ClassLoader loader,
 46.1897 +     *                                         boolean reload)
 46.1898 +     *                          throws IllegalAccessException,
 46.1899 +     *                                 InstantiationException,
 46.1900 +     *                                 IOException {
 46.1901 +     *             if (baseName == null || locale == null
 46.1902 +     *                   || format == null || loader == null)
 46.1903 +     *                 throw new NullPointerException();
 46.1904 +     *             ResourceBundle bundle = null;
 46.1905 +     *             if (format.equals("xml")) {
 46.1906 +     *                 String bundleName = toBundleName(baseName, locale);
 46.1907 +     *                 String resourceName = toResourceName(bundleName, format);
 46.1908 +     *                 InputStream stream = null;
 46.1909 +     *                 if (reload) {
 46.1910 +     *                     URL url = loader.getResource(resourceName);
 46.1911 +     *                     if (url != null) {
 46.1912 +     *                         URLConnection connection = url.openConnection();
 46.1913 +     *                         if (connection != null) {
 46.1914 +     *                             // Disable caches to get fresh data for
 46.1915 +     *                             // reloading.
 46.1916 +     *                             connection.setUseCaches(false);
 46.1917 +     *                             stream = connection.getInputStream();
 46.1918 +     *                         }
 46.1919 +     *                     }
 46.1920 +     *                 } else {
 46.1921 +     *                     stream = loader.getResourceAsStream(resourceName);
 46.1922 +     *                 }
 46.1923 +     *                 if (stream != null) {
 46.1924 +     *                     BufferedInputStream bis = new BufferedInputStream(stream);
 46.1925 +     *                     bundle = new XMLResourceBundle(bis);
 46.1926 +     *                     bis.close();
 46.1927 +     *                 }
 46.1928 +     *             }
 46.1929 +     *             return bundle;
 46.1930 +     *         }
 46.1931 +     *     });
 46.1932 +     *
 46.1933 +     * ...
 46.1934 +     *
 46.1935 +     * private static class XMLResourceBundle extends ResourceBundle {
 46.1936 +     *     private Properties props;
 46.1937 +     *     XMLResourceBundle(InputStream stream) throws IOException {
 46.1938 +     *         props = new Properties();
 46.1939 +     *         props.loadFromXML(stream);
 46.1940 +     *     }
 46.1941 +     *     protected Object handleGetObject(String key) {
 46.1942 +     *         return props.getProperty(key);
 46.1943 +     *     }
 46.1944 +     *     public Enumeration&lt;String&gt; getKeys() {
 46.1945 +     *         ...
 46.1946 +     *     }
 46.1947 +     * }
 46.1948 +     * </pre>
 46.1949 +     *
 46.1950 +     * @since 1.6
 46.1951 +     */
 46.1952 +    public static class Control {
 46.1953 +        /**
 46.1954 +         * The default format <code>List</code>, which contains the strings
 46.1955 +         * <code>"java.class"</code> and <code>"java.properties"</code>, in
 46.1956 +         * this order. This <code>List</code> is {@linkplain
 46.1957 +         * Collections#unmodifiableList(List) unmodifiable}.
 46.1958 +         *
 46.1959 +         * @see #getFormats(String)
 46.1960 +         */
 46.1961 +        public static final List<String> FORMAT_DEFAULT
 46.1962 +            = Collections.unmodifiableList(Arrays.asList("java.class",
 46.1963 +                                                         "java.properties"));
 46.1964 +
 46.1965 +        /**
 46.1966 +         * The class-only format <code>List</code> containing
 46.1967 +         * <code>"java.class"</code>. This <code>List</code> is {@linkplain
 46.1968 +         * Collections#unmodifiableList(List) unmodifiable}.
 46.1969 +         *
 46.1970 +         * @see #getFormats(String)
 46.1971 +         */
 46.1972 +        public static final List<String> FORMAT_CLASS
 46.1973 +            = Collections.unmodifiableList(Arrays.asList("java.class"));
 46.1974 +
 46.1975 +        /**
 46.1976 +         * The properties-only format <code>List</code> containing
 46.1977 +         * <code>"java.properties"</code>. This <code>List</code> is
 46.1978 +         * {@linkplain Collections#unmodifiableList(List) unmodifiable}.
 46.1979 +         *
 46.1980 +         * @see #getFormats(String)
 46.1981 +         */
 46.1982 +        public static final List<String> FORMAT_PROPERTIES
 46.1983 +            = Collections.unmodifiableList(Arrays.asList("java.properties"));
 46.1984 +
 46.1985 +        /**
 46.1986 +         * The time-to-live constant for not caching loaded resource bundle
 46.1987 +         * instances.
 46.1988 +         *
 46.1989 +         * @see #getTimeToLive(String, Locale)
 46.1990 +         */
 46.1991 +        public static final long TTL_DONT_CACHE = -1;
 46.1992 +
 46.1993 +        /**
 46.1994 +         * The time-to-live constant for disabling the expiration control
 46.1995 +         * for loaded resource bundle instances in the cache.
 46.1996 +         *
 46.1997 +         * @see #getTimeToLive(String, Locale)
 46.1998 +         */
 46.1999 +        public static final long TTL_NO_EXPIRATION_CONTROL = -2;
 46.2000 +
 46.2001 +        private static final Control INSTANCE = new Control();
 46.2002 +
 46.2003 +        /**
 46.2004 +         * Sole constructor. (For invocation by subclass constructors,
 46.2005 +         * typically implicit.)
 46.2006 +         */
 46.2007 +        protected Control() {
 46.2008 +        }
 46.2009 +
 46.2010 +        /**
 46.2011 +         * Returns a <code>ResourceBundle.Control</code> in which the {@link
 46.2012 +         * #getFormats(String) getFormats} method returns the specified
 46.2013 +         * <code>formats</code>. The <code>formats</code> must be equal to
 46.2014 +         * one of {@link Control#FORMAT_PROPERTIES}, {@link
 46.2015 +         * Control#FORMAT_CLASS} or {@link
 46.2016 +         * Control#FORMAT_DEFAULT}. <code>ResourceBundle.Control</code>
 46.2017 +         * instances returned by this method are singletons and thread-safe.
 46.2018 +         *
 46.2019 +         * <p>Specifying {@link Control#FORMAT_DEFAULT} is equivalent to
 46.2020 +         * instantiating the <code>ResourceBundle.Control</code> class,
 46.2021 +         * except that this method returns a singleton.
 46.2022 +         *
 46.2023 +         * @param formats
 46.2024 +         *        the formats to be returned by the
 46.2025 +         *        <code>ResourceBundle.Control.getFormats</code> method
 46.2026 +         * @return a <code>ResourceBundle.Control</code> supporting the
 46.2027 +         *        specified <code>formats</code>
 46.2028 +         * @exception NullPointerException
 46.2029 +         *        if <code>formats</code> is <code>null</code>
 46.2030 +         * @exception IllegalArgumentException
 46.2031 +         *        if <code>formats</code> is unknown
 46.2032 +         */
 46.2033 +        public static final Control getControl(List<String> formats) {
 46.2034 +            if (formats.equals(Control.FORMAT_PROPERTIES)) {
 46.2035 +                return SingleFormatControl.PROPERTIES_ONLY;
 46.2036 +            }
 46.2037 +            if (formats.equals(Control.FORMAT_CLASS)) {
 46.2038 +                return SingleFormatControl.CLASS_ONLY;
 46.2039 +            }
 46.2040 +            if (formats.equals(Control.FORMAT_DEFAULT)) {
 46.2041 +                return Control.INSTANCE;
 46.2042 +            }
 46.2043 +            throw new IllegalArgumentException();
 46.2044 +        }
 46.2045 +
 46.2046 +        /**
 46.2047 +         * Returns a <code>ResourceBundle.Control</code> in which the {@link
 46.2048 +         * #getFormats(String) getFormats} method returns the specified
 46.2049 +         * <code>formats</code> and the {@link
 46.2050 +         * Control#getFallbackLocale(String, Locale) getFallbackLocale}
 46.2051 +         * method returns <code>null</code>. The <code>formats</code> must
 46.2052 +         * be equal to one of {@link Control#FORMAT_PROPERTIES}, {@link
 46.2053 +         * Control#FORMAT_CLASS} or {@link Control#FORMAT_DEFAULT}.
 46.2054 +         * <code>ResourceBundle.Control</code> instances returned by this
 46.2055 +         * method are singletons and thread-safe.
 46.2056 +         *
 46.2057 +         * @param formats
 46.2058 +         *        the formats to be returned by the
 46.2059 +         *        <code>ResourceBundle.Control.getFormats</code> method
 46.2060 +         * @return a <code>ResourceBundle.Control</code> supporting the
 46.2061 +         *        specified <code>formats</code> with no fallback
 46.2062 +         *        <code>Locale</code> support
 46.2063 +         * @exception NullPointerException
 46.2064 +         *        if <code>formats</code> is <code>null</code>
 46.2065 +         * @exception IllegalArgumentException
 46.2066 +         *        if <code>formats</code> is unknown
 46.2067 +         */
 46.2068 +        public static final Control getNoFallbackControl(List<String> formats) {
 46.2069 +            if (formats.equals(Control.FORMAT_DEFAULT)) {
 46.2070 +                return NoFallbackControl.NO_FALLBACK;
 46.2071 +            }
 46.2072 +            if (formats.equals(Control.FORMAT_PROPERTIES)) {
 46.2073 +                return NoFallbackControl.PROPERTIES_ONLY_NO_FALLBACK;
 46.2074 +            }
 46.2075 +            if (formats.equals(Control.FORMAT_CLASS)) {
 46.2076 +                return NoFallbackControl.CLASS_ONLY_NO_FALLBACK;
 46.2077 +            }
 46.2078 +            throw new IllegalArgumentException();
 46.2079 +        }
 46.2080 +
 46.2081 +        /**
 46.2082 +         * Returns a <code>List</code> of <code>String</code>s containing
 46.2083 +         * formats to be used to load resource bundles for the given
 46.2084 +         * <code>baseName</code>. The <code>ResourceBundle.getBundle</code>
 46.2085 +         * factory method tries to load resource bundles with formats in the
 46.2086 +         * order specified by the list. The list returned by this method
 46.2087 +         * must have at least one <code>String</code>. The predefined
 46.2088 +         * formats are <code>"java.class"</code> for class-based resource
 46.2089 +         * bundles and <code>"java.properties"</code> for {@linkplain
 46.2090 +         * PropertyResourceBundle properties-based} ones. Strings starting
 46.2091 +         * with <code>"java."</code> are reserved for future extensions and
 46.2092 +         * must not be used by application-defined formats.
 46.2093 +         *
 46.2094 +         * <p>It is not a requirement to return an immutable (unmodifiable)
 46.2095 +         * <code>List</code>.  However, the returned <code>List</code> must
 46.2096 +         * not be mutated after it has been returned by
 46.2097 +         * <code>getFormats</code>.
 46.2098 +         *
 46.2099 +         * <p>The default implementation returns {@link #FORMAT_DEFAULT} so
 46.2100 +         * that the <code>ResourceBundle.getBundle</code> factory method
 46.2101 +         * looks up first class-based resource bundles, then
 46.2102 +         * properties-based ones.
 46.2103 +         *
 46.2104 +         * @param baseName
 46.2105 +         *        the base name of the resource bundle, a fully qualified class
 46.2106 +         *        name
 46.2107 +         * @return a <code>List</code> of <code>String</code>s containing
 46.2108 +         *        formats for loading resource bundles.
 46.2109 +         * @exception NullPointerException
 46.2110 +         *        if <code>baseName</code> is null
 46.2111 +         * @see #FORMAT_DEFAULT
 46.2112 +         * @see #FORMAT_CLASS
 46.2113 +         * @see #FORMAT_PROPERTIES
 46.2114 +         */
 46.2115 +        public List<String> getFormats(String baseName) {
 46.2116 +            if (baseName == null) {
 46.2117 +                throw new NullPointerException();
 46.2118 +            }
 46.2119 +            return FORMAT_DEFAULT;
 46.2120 +        }
 46.2121 +
 46.2122 +        /**
 46.2123 +         * Returns a <code>List</code> of <code>Locale</code>s as candidate
 46.2124 +         * locales for <code>baseName</code> and <code>locale</code>. This
 46.2125 +         * method is called by the <code>ResourceBundle.getBundle</code>
 46.2126 +         * factory method each time the factory method tries finding a
 46.2127 +         * resource bundle for a target <code>Locale</code>.
 46.2128 +         *
 46.2129 +         * <p>The sequence of the candidate locales also corresponds to the
 46.2130 +         * runtime resource lookup path (also known as the <I>parent
 46.2131 +         * chain</I>), if the corresponding resource bundles for the
 46.2132 +         * candidate locales exist and their parents are not defined by
 46.2133 +         * loaded resource bundles themselves.  The last element of the list
 46.2134 +         * must be a {@linkplain Locale#ROOT root locale} if it is desired to
 46.2135 +         * have the base bundle as the terminal of the parent chain.
 46.2136 +         *
 46.2137 +         * <p>If the given locale is equal to <code>Locale.ROOT</code> (the
 46.2138 +         * root locale), a <code>List</code> containing only the root
 46.2139 +         * <code>Locale</code> must be returned. In this case, the
 46.2140 +         * <code>ResourceBundle.getBundle</code> factory method loads only
 46.2141 +         * the base bundle as the resulting resource bundle.
 46.2142 +         *
 46.2143 +         * <p>It is not a requirement to return an immutable (unmodifiable)
 46.2144 +         * <code>List</code>. However, the returned <code>List</code> must not
 46.2145 +         * be mutated after it has been returned by
 46.2146 +         * <code>getCandidateLocales</code>.
 46.2147 +         *
 46.2148 +         * <p>The default implementation returns a <code>List</code> containing
 46.2149 +         * <code>Locale</code>s using the rules described below.  In the
 46.2150 +         * description below, <em>L</em>, <em>S</em>, <em>C</em> and <em>V</em>
 46.2151 +         * respectively represent non-empty language, script, country, and
 46.2152 +         * variant.  For example, [<em>L</em>, <em>C</em>] represents a
 46.2153 +         * <code>Locale</code> that has non-empty values only for language and
 46.2154 +         * country.  The form <em>L</em>("xx") represents the (non-empty)
 46.2155 +         * language value is "xx".  For all cases, <code>Locale</code>s whose
 46.2156 +         * final component values are empty strings are omitted.
 46.2157 +         *
 46.2158 +         * <ol><li>For an input <code>Locale</code> with an empty script value,
 46.2159 +         * append candidate <code>Locale</code>s by omitting the final component
 46.2160 +         * one by one as below:
 46.2161 +         *
 46.2162 +         * <ul>
 46.2163 +         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
 46.2164 +         * <li> [<em>L</em>, <em>C</em>]
 46.2165 +         * <li> [<em>L</em>]
 46.2166 +         * <li> <code>Locale.ROOT</code>
 46.2167 +         * </ul>
 46.2168 +         *
 46.2169 +         * <li>For an input <code>Locale</code> with a non-empty script value,
 46.2170 +         * append candidate <code>Locale</code>s by omitting the final component
 46.2171 +         * up to language, then append candidates generated from the
 46.2172 +         * <code>Locale</code> with country and variant restored:
 46.2173 +         *
 46.2174 +         * <ul>
 46.2175 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V</em>]
 46.2176 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
 46.2177 +         * <li> [<em>L</em>, <em>S</em>]
 46.2178 +         * <li> [<em>L</em>, <em>C</em>, <em>V</em>]
 46.2179 +         * <li> [<em>L</em>, <em>C</em>]
 46.2180 +         * <li> [<em>L</em>]
 46.2181 +         * <li> <code>Locale.ROOT</code>
 46.2182 +         * </ul>
 46.2183 +         *
 46.2184 +         * <li>For an input <code>Locale</code> with a variant value consisting
 46.2185 +         * of multiple subtags separated by underscore, generate candidate
 46.2186 +         * <code>Locale</code>s by omitting the variant subtags one by one, then
 46.2187 +         * insert them after every occurence of <code> Locale</code>s with the
 46.2188 +         * full variant value in the original list.  For example, if the
 46.2189 +         * the variant consists of two subtags <em>V1</em> and <em>V2</em>:
 46.2190 +         *
 46.2191 +         * <ul>
 46.2192 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
 46.2193 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>, <em>V1</em>]
 46.2194 +         * <li> [<em>L</em>, <em>S</em>, <em>C</em>]
 46.2195 +         * <li> [<em>L</em>, <em>S</em>]
 46.2196 +         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>, <em>V2</em>]
 46.2197 +         * <li> [<em>L</em>, <em>C</em>, <em>V1</em>]
 46.2198 +         * <li> [<em>L</em>, <em>C</em>]
 46.2199 +         * <li> [<em>L</em>]
 46.2200 +         * <li> <code>Locale.ROOT</code>
 46.2201 +         * </ul>
 46.2202 +         *
 46.2203 +         * <li>Special cases for Chinese.  When an input <code>Locale</code> has the
 46.2204 +         * language "zh" (Chinese) and an empty script value, either "Hans" (Simplified) or
 46.2205 +         * "Hant" (Traditional) might be supplied, depending on the country.
 46.2206 +         * When the country is "CN" (China) or "SG" (Singapore), "Hans" is supplied.
 46.2207 +         * When the country is "HK" (Hong Kong SAR China), "MO" (Macau SAR China),
 46.2208 +         * or "TW" (Taiwan), "Hant" is supplied.  For all other countries or when the country
 46.2209 +         * is empty, no script is supplied.  For example, for <code>Locale("zh", "CN")
 46.2210 +         * </code>, the candidate list will be:
 46.2211 +         * <ul>
 46.2212 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hans"), <em>C</em>("CN")]
 46.2213 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hans")]
 46.2214 +         * <li> [<em>L</em>("zh"), <em>C</em>("CN")]
 46.2215 +         * <li> [<em>L</em>("zh")]
 46.2216 +         * <li> <code>Locale.ROOT</code>
 46.2217 +         * </ul>
 46.2218 +         *
 46.2219 +         * For <code>Locale("zh", "TW")</code>, the candidate list will be:
 46.2220 +         * <ul>
 46.2221 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hant"), <em>C</em>("TW")]
 46.2222 +         * <li> [<em>L</em>("zh"), <em>S</em>("Hant")]
 46.2223 +         * <li> [<em>L</em>("zh"), <em>C</em>("TW")]
 46.2224 +         * <li> [<em>L</em>("zh")]
 46.2225 +         * <li> <code>Locale.ROOT</code>
 46.2226 +         * </ul>
 46.2227 +         *
 46.2228 +         * <li>Special cases for Norwegian.  Both <code>Locale("no", "NO",
 46.2229 +         * "NY")</code> and <code>Locale("nn", "NO")</code> represent Norwegian
 46.2230 +         * Nynorsk.  When a locale's language is "nn", the standard candidate
 46.2231 +         * list is generated up to [<em>L</em>("nn")], and then the following
 46.2232 +         * candidates are added:
 46.2233 +         *
 46.2234 +         * <ul><li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("NY")]
 46.2235 +         * <li> [<em>L</em>("no"), <em>C</em>("NO")]
 46.2236 +         * <li> [<em>L</em>("no")]
 46.2237 +         * <li> <code>Locale.ROOT</code>
 46.2238 +         * </ul>
 46.2239 +         *
 46.2240 +         * If the locale is exactly <code>Locale("no", "NO", "NY")</code>, it is first
 46.2241 +         * converted to <code>Locale("nn", "NO")</code> and then the above procedure is
 46.2242 +         * followed.
 46.2243 +         *
 46.2244 +         * <p>Also, Java treats the language "no" as a synonym of Norwegian
 46.2245 +         * Bokm&#xE5;l "nb".  Except for the single case <code>Locale("no",
 46.2246 +         * "NO", "NY")</code> (handled above), when an input <code>Locale</code>
 46.2247 +         * has language "no" or "nb", candidate <code>Locale</code>s with
 46.2248 +         * language code "no" and "nb" are interleaved, first using the
 46.2249 +         * requested language, then using its synonym. For example,
 46.2250 +         * <code>Locale("nb", "NO", "POSIX")</code> generates the following
 46.2251 +         * candidate list:
 46.2252 +         *
 46.2253 +         * <ul>
 46.2254 +         * <li> [<em>L</em>("nb"), <em>C</em>("NO"), <em>V</em>("POSIX")]
 46.2255 +         * <li> [<em>L</em>("no"), <em>C</em>("NO"), <em>V</em>("POSIX")]
 46.2256 +         * <li> [<em>L</em>("nb"), <em>C</em>("NO")]
 46.2257 +         * <li> [<em>L</em>("no"), <em>C</em>("NO")]
 46.2258 +         * <li> [<em>L</em>("nb")]
 46.2259 +         * <li> [<em>L</em>("no")]
 46.2260 +         * <li> <code>Locale.ROOT</code>
 46.2261 +         * </ul>
 46.2262 +         *
 46.2263 +         * <code>Locale("no", "NO", "POSIX")</code> would generate the same list
 46.2264 +         * except that locales with "no" would appear before the corresponding
 46.2265 +         * locales with "nb".</li>
 46.2266 +         *
 46.2267 +         * </li>
 46.2268 +         * </ol>
 46.2269 +         *
 46.2270 +         * <p>The default implementation uses an {@link ArrayList} that
 46.2271 +         * overriding implementations may modify before returning it to the
 46.2272 +         * caller. However, a subclass must not modify it after it has
 46.2273 +         * been returned by <code>getCandidateLocales</code>.
 46.2274 +         *
 46.2275 +         * <p>For example, if the given <code>baseName</code> is "Messages"
 46.2276 +         * and the given <code>locale</code> is
 46.2277 +         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then a
 46.2278 +         * <code>List</code> of <code>Locale</code>s:
 46.2279 +         * <pre>
 46.2280 +         *     Locale("ja", "", "XX")
 46.2281 +         *     Locale("ja")
 46.2282 +         *     Locale.ROOT
 46.2283 +         * </pre>
 46.2284 +         * is returned. And if the resource bundles for the "ja" and
 46.2285 +         * "" <code>Locale</code>s are found, then the runtime resource
 46.2286 +         * lookup path (parent chain) is:
 46.2287 +         * <pre>
 46.2288 +         *     Messages_ja -> Messages
 46.2289 +         * </pre>
 46.2290 +         *
 46.2291 +         * @param baseName
 46.2292 +         *        the base name of the resource bundle, a fully
 46.2293 +         *        qualified class name
 46.2294 +         * @param locale
 46.2295 +         *        the locale for which a resource bundle is desired
 46.2296 +         * @return a <code>List</code> of candidate
 46.2297 +         *        <code>Locale</code>s for the given <code>locale</code>
 46.2298 +         * @exception NullPointerException
 46.2299 +         *        if <code>baseName</code> or <code>locale</code> is
 46.2300 +         *        <code>null</code>
 46.2301 +         */
 46.2302 +        public List<Locale> getCandidateLocales(String baseName, Locale locale) {
 46.2303 +            if (baseName == null) {
 46.2304 +                throw new NullPointerException();
 46.2305 +            }
 46.2306 +            return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
 46.2307 +        }
 46.2308 +
 46.2309 +        private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
 46.2310 +
 46.2311 +        private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
 46.2312 +            protected List<Locale> createObject(BaseLocale base) {
 46.2313 +                String language = base.getLanguage();
 46.2314 +                String script = base.getScript();
 46.2315 +                String region = base.getRegion();
 46.2316 +                String variant = base.getVariant();
 46.2317 +
 46.2318 +                // Special handling for Norwegian
 46.2319 +                boolean isNorwegianBokmal = false;
 46.2320 +                boolean isNorwegianNynorsk = false;
 46.2321 +                if (language.equals("no")) {
 46.2322 +                    if (region.equals("NO") && variant.equals("NY")) {
 46.2323 +                        variant = "";
 46.2324 +                        isNorwegianNynorsk = true;
 46.2325 +                    } else {
 46.2326 +                        isNorwegianBokmal = true;
 46.2327 +                    }
 46.2328 +                }
 46.2329 +                if (language.equals("nb") || isNorwegianBokmal) {
 46.2330 +                    List<Locale> tmpList = getDefaultList("nb", script, region, variant);
 46.2331 +                    // Insert a locale replacing "nb" with "no" for every list entry
 46.2332 +                    List<Locale> bokmalList = new LinkedList<>();
 46.2333 +                    for (Locale l : tmpList) {
 46.2334 +                        bokmalList.add(l);
 46.2335 +                        if (l.getLanguage().length() == 0) {
 46.2336 +                            break;
 46.2337 +                        }
 46.2338 +                        bokmalList.add(Locale.getInstance("no", l.getScript(), l.getCountry(),
 46.2339 +                                l.getVariant(), null));
 46.2340 +                    }
 46.2341 +                    return bokmalList;
 46.2342 +                } else if (language.equals("nn") || isNorwegianNynorsk) {
 46.2343 +                    // Insert no_NO_NY, no_NO, no after nn
 46.2344 +                    List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
 46.2345 +                    int idx = nynorskList.size() - 1;
 46.2346 +                    nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
 46.2347 +                    nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
 46.2348 +                    nynorskList.add(idx++, Locale.getInstance("no", "", ""));
 46.2349 +                    return nynorskList;
 46.2350 +                }
 46.2351 +                // Special handling for Chinese
 46.2352 +                else if (language.equals("zh")) {
 46.2353 +                    if (script.length() == 0 && region.length() > 0) {
 46.2354 +                        // Supply script for users who want to use zh_Hans/zh_Hant
 46.2355 +                        // as bundle names (recommended for Java7+)
 46.2356 +                        if (region.equals("TW") || region.equals("HK") || region.equals("MO")) {
 46.2357 +                            script = "Hant";
 46.2358 +                        } else if (region.equals("CN") || region.equals("SG")) {
 46.2359 +                            script = "Hans";
 46.2360 +                        }
 46.2361 +                    } else if (script.length() > 0 && region.length() == 0) {
 46.2362 +                        // Supply region(country) for users who still package Chinese
 46.2363 +                        // bundles using old convension.
 46.2364 +                        if (script.equals("Hans")) {
 46.2365 +                            region = "CN";
 46.2366 +                        } else if (script.equals("Hant")) {
 46.2367 +                            region = "TW";
 46.2368 +                        }
 46.2369 +                    }
 46.2370 +                }
 46.2371 +
 46.2372 +                return getDefaultList(language, script, region, variant);
 46.2373 +            }
 46.2374 +
 46.2375 +            private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
 46.2376 +                List<String> variants = null;
 46.2377 +
 46.2378 +                if (variant.length() > 0) {
 46.2379 +                    variants = new LinkedList<>();
 46.2380 +                    int idx = variant.length();
 46.2381 +                    while (idx != -1) {
 46.2382 +                        variants.add(variant.substring(0, idx));
 46.2383 +                        idx = variant.lastIndexOf('_', --idx);
 46.2384 +                    }
 46.2385 +                }
 46.2386 +
 46.2387 +                List<Locale> list = new LinkedList<>();
 46.2388 +
 46.2389 +                if (variants != null) {
 46.2390 +                    for (String v : variants) {
 46.2391 +                        list.add(Locale.getInstance(language, script, region, v, null));
 46.2392 +                    }
 46.2393 +                }
 46.2394 +                if (region.length() > 0) {
 46.2395 +                    list.add(Locale.getInstance(language, script, region, "", null));
 46.2396 +                }
 46.2397 +                if (script.length() > 0) {
 46.2398 +                    list.add(Locale.getInstance(language, script, "", "", null));
 46.2399 +
 46.2400 +                    // With script, after truncating variant, region and script,
 46.2401 +                    // start over without script.
 46.2402 +                    if (variants != null) {
 46.2403 +                        for (String v : variants) {
 46.2404 +                            list.add(Locale.getInstance(language, "", region, v, null));
 46.2405 +                        }
 46.2406 +                    }
 46.2407 +                    if (region.length() > 0) {
 46.2408 +                        list.add(Locale.getInstance(language, "", region, "", null));
 46.2409 +                    }
 46.2410 +                }
 46.2411 +                if (language.length() > 0) {
 46.2412 +                    list.add(Locale.getInstance(language, "", "", "", null));
 46.2413 +                }
 46.2414 +                // Add root locale at the end
 46.2415 +                list.add(Locale.ROOT);
 46.2416 +
 46.2417 +                return list;
 46.2418 +            }
 46.2419 +        }
 46.2420 +
 46.2421 +        /**
 46.2422 +         * Returns a <code>Locale</code> to be used as a fallback locale for
 46.2423 +         * further resource bundle searches by the
 46.2424 +         * <code>ResourceBundle.getBundle</code> factory method. This method
 46.2425 +         * is called from the factory method every time when no resulting
 46.2426 +         * resource bundle has been found for <code>baseName</code> and
 46.2427 +         * <code>locale</code>, where locale is either the parameter for
 46.2428 +         * <code>ResourceBundle.getBundle</code> or the previous fallback
 46.2429 +         * locale returned by this method.
 46.2430 +         *
 46.2431 +         * <p>The method returns <code>null</code> if no further fallback
 46.2432 +         * search is desired.
 46.2433 +         *
 46.2434 +         * <p>The default implementation returns the {@linkplain
 46.2435 +         * Locale#getDefault() default <code>Locale</code>} if the given
 46.2436 +         * <code>locale</code> isn't the default one.  Otherwise,
 46.2437 +         * <code>null</code> is returned.
 46.2438 +         *
 46.2439 +         * @param baseName
 46.2440 +         *        the base name of the resource bundle, a fully
 46.2441 +         *        qualified class name for which
 46.2442 +         *        <code>ResourceBundle.getBundle</code> has been
 46.2443 +         *        unable to find any resource bundles (except for the
 46.2444 +         *        base bundle)
 46.2445 +         * @param locale
 46.2446 +         *        the <code>Locale</code> for which
 46.2447 +         *        <code>ResourceBundle.getBundle</code> has been
 46.2448 +         *        unable to find any resource bundles (except for the
 46.2449 +         *        base bundle)
 46.2450 +         * @return a <code>Locale</code> for the fallback search,
 46.2451 +         *        or <code>null</code> if no further fallback search
 46.2452 +         *        is desired.
 46.2453 +         * @exception NullPointerException
 46.2454 +         *        if <code>baseName</code> or <code>locale</code>
 46.2455 +         *        is <code>null</code>
 46.2456 +         */
 46.2457 +        public Locale getFallbackLocale(String baseName, Locale locale) {
 46.2458 +            if (baseName == null) {
 46.2459 +                throw new NullPointerException();
 46.2460 +            }
 46.2461 +            Locale defaultLocale = Locale.getDefault();
 46.2462 +            return locale.equals(defaultLocale) ? null : defaultLocale;
 46.2463 +        }
 46.2464 +
 46.2465 +        /**
 46.2466 +         * Instantiates a resource bundle for the given bundle name of the
 46.2467 +         * given format and locale, using the given class loader if
 46.2468 +         * necessary. This method returns <code>null</code> if there is no
 46.2469 +         * resource bundle available for the given parameters. If a resource
 46.2470 +         * bundle can't be instantiated due to an unexpected error, the
 46.2471 +         * error must be reported by throwing an <code>Error</code> or
 46.2472 +         * <code>Exception</code> rather than simply returning
 46.2473 +         * <code>null</code>.
 46.2474 +         *
 46.2475 +         * <p>If the <code>reload</code> flag is <code>true</code>, it
 46.2476 +         * indicates that this method is being called because the previously
 46.2477 +         * loaded resource bundle has expired.
 46.2478 +         *
 46.2479 +         * <p>The default implementation instantiates a
 46.2480 +         * <code>ResourceBundle</code> as follows.
 46.2481 +         *
 46.2482 +         * <ul>
 46.2483 +         *
 46.2484 +         * <li>The bundle name is obtained by calling {@link
 46.2485 +         * #toBundleName(String, Locale) toBundleName(baseName,
 46.2486 +         * locale)}.</li>
 46.2487 +         *
 46.2488 +         * <li>If <code>format</code> is <code>"java.class"</code>, the
 46.2489 +         * {@link Class} specified by the bundle name is loaded by calling
 46.2490 +         * {@link ClassLoader#loadClass(String)}. Then, a
 46.2491 +         * <code>ResourceBundle</code> is instantiated by calling {@link
 46.2492 +         * Class#newInstance()}.  Note that the <code>reload</code> flag is
 46.2493 +         * ignored for loading class-based resource bundles in this default
 46.2494 +         * implementation.</li>
 46.2495 +         *
 46.2496 +         * <li>If <code>format</code> is <code>"java.properties"</code>,
 46.2497 +         * {@link #toResourceName(String, String) toResourceName(bundlename,
 46.2498 +         * "properties")} is called to get the resource name.
 46.2499 +         * If <code>reload</code> is <code>true</code>, {@link
 46.2500 +         * ClassLoader#getResource(String) load.getResource} is called
 46.2501 +         * to get a {@link URL} for creating a {@link
 46.2502 +         * URLConnection}. This <code>URLConnection</code> is used to
 46.2503 +         * {@linkplain URLConnection#setUseCaches(boolean) disable the
 46.2504 +         * caches} of the underlying resource loading layers,
 46.2505 +         * and to {@linkplain URLConnection#getInputStream() get an
 46.2506 +         * <code>InputStream</code>}.
 46.2507 +         * Otherwise, {@link ClassLoader#getResourceAsStream(String)
 46.2508 +         * loader.getResourceAsStream} is called to get an {@link
 46.2509 +         * InputStream}. Then, a {@link
 46.2510 +         * PropertyResourceBundle} is constructed with the
 46.2511 +         * <code>InputStream</code>.</li>
 46.2512 +         *
 46.2513 +         * <li>If <code>format</code> is neither <code>"java.class"</code>
 46.2514 +         * nor <code>"java.properties"</code>, an
 46.2515 +         * <code>IllegalArgumentException</code> is thrown.</li>
 46.2516 +         *
 46.2517 +         * </ul>
 46.2518 +         *
 46.2519 +         * @param baseName
 46.2520 +         *        the base bundle name of the resource bundle, a fully
 46.2521 +         *        qualified class name
 46.2522 +         * @param locale
 46.2523 +         *        the locale for which the resource bundle should be
 46.2524 +         *        instantiated
 46.2525 +         * @param format
 46.2526 +         *        the resource bundle format to be loaded
 46.2527 +         * @param loader
 46.2528 +         *        the <code>ClassLoader</code> to use to load the bundle
 46.2529 +         * @param reload
 46.2530 +         *        the flag to indicate bundle reloading; <code>true</code>
 46.2531 +         *        if reloading an expired resource bundle,
 46.2532 +         *        <code>false</code> otherwise
 46.2533 +         * @return the resource bundle instance,
 46.2534 +         *        or <code>null</code> if none could be found.
 46.2535 +         * @exception NullPointerException
 46.2536 +         *        if <code>bundleName</code>, <code>locale</code>,
 46.2537 +         *        <code>format</code>, or <code>loader</code> is
 46.2538 +         *        <code>null</code>, or if <code>null</code> is returned by
 46.2539 +         *        {@link #toBundleName(String, Locale) toBundleName}
 46.2540 +         * @exception IllegalArgumentException
 46.2541 +         *        if <code>format</code> is unknown, or if the resource
 46.2542 +         *        found for the given parameters contains malformed data.
 46.2543 +         * @exception ClassCastException
 46.2544 +         *        if the loaded class cannot be cast to <code>ResourceBundle</code>
 46.2545 +         * @exception IllegalAccessException
 46.2546 +         *        if the class or its nullary constructor is not
 46.2547 +         *        accessible.
 46.2548 +         * @exception InstantiationException
 46.2549 +         *        if the instantiation of a class fails for some other
 46.2550 +         *        reason.
 46.2551 +         * @exception ExceptionInInitializerError
 46.2552 +         *        if the initialization provoked by this method fails.
 46.2553 +         * @exception SecurityException
 46.2554 +         *        If a security manager is present and creation of new
 46.2555 +         *        instances is denied. See {@link Class#newInstance()}
 46.2556 +         *        for details.
 46.2557 +         * @exception IOException
 46.2558 +         *        if an error occurred when reading resources using
 46.2559 +         *        any I/O operations
 46.2560 +         */
 46.2561 +        public ResourceBundle newBundle(String baseName, Locale locale, String format,
 46.2562 +                                        ClassLoader loader, boolean reload)
 46.2563 +                    throws IllegalAccessException, InstantiationException, IOException {
 46.2564 +            String bundleName = toBundleName(baseName, locale);
 46.2565 +            ResourceBundle bundle = null;
 46.2566 +            if (format.equals("java.class")) {
 46.2567 +                try {
 46.2568 +                    Class<? extends ResourceBundle> bundleClass
 46.2569 +                        = (Class<? extends ResourceBundle>)loader.loadClass(bundleName);
 46.2570 +
 46.2571 +                    // If the class isn't a ResourceBundle subclass, throw a
 46.2572 +                    // ClassCastException.
 46.2573 +                    if (ResourceBundle.class.isAssignableFrom(bundleClass)) {
 46.2574 +                        bundle = bundleClass.newInstance();
 46.2575 +                    } else {
 46.2576 +                        throw new ClassCastException(bundleClass.getName()
 46.2577 +                                     + " cannot be cast to ResourceBundle");
 46.2578 +                    }
 46.2579 +                } catch (ClassNotFoundException e) {
 46.2580 +                }
 46.2581 +            } else if (format.equals("java.properties")) {
 46.2582 +                final String resourceName = toResourceName(bundleName, "properties");
 46.2583 +                final ClassLoader classLoader = loader;
 46.2584 +                final boolean reloadFlag = reload;
 46.2585 +                InputStream stream = null;
 46.2586 +                try {
 46.2587 +                    stream = AccessController.doPrivileged(
 46.2588 +                        new PrivilegedExceptionAction<InputStream>() {
 46.2589 +                            public InputStream run() throws IOException {
 46.2590 +                                InputStream is = null;
 46.2591 +                                if (reloadFlag) {
 46.2592 +                                    URL url = classLoader.getResource(resourceName);
 46.2593 +                                    if (url != null) {
 46.2594 +                                        URLConnection connection = url.openConnection();
 46.2595 +                                        if (connection != null) {
 46.2596 +                                            // Disable caches to get fresh data for
 46.2597 +                                            // reloading.
 46.2598 +                                            connection.setUseCaches(false);
 46.2599 +                                            is = connection.getInputStream();
 46.2600 +                                        }
 46.2601 +                                    }
 46.2602 +                                } else {
 46.2603 +                                    is = classLoader.getResourceAsStream(resourceName);
 46.2604 +                                }
 46.2605 +                                return is;
 46.2606 +                            }
 46.2607 +                        });
 46.2608 +                } catch (PrivilegedActionException e) {
 46.2609 +                    throw (IOException) e.getException();
 46.2610 +                }
 46.2611 +                if (stream != null) {
 46.2612 +                    try {
 46.2613 +                        bundle = new PropertyResourceBundle(stream);
 46.2614 +                    } finally {
 46.2615 +                        stream.close();
 46.2616 +                    }
 46.2617 +                }
 46.2618 +            } else {
 46.2619 +                throw new IllegalArgumentException("unknown format: " + format);
 46.2620 +            }
 46.2621 +            return bundle;
 46.2622 +        }
 46.2623 +
 46.2624 +        /**
 46.2625 +         * Returns the time-to-live (TTL) value for resource bundles that
 46.2626 +         * are loaded under this
 46.2627 +         * <code>ResourceBundle.Control</code>. Positive time-to-live values
 46.2628 +         * specify the number of milliseconds a bundle can remain in the
 46.2629 +         * cache without being validated against the source data from which
 46.2630 +         * it was constructed. The value 0 indicates that a bundle must be
 46.2631 +         * validated each time it is retrieved from the cache. {@link
 46.2632 +         * #TTL_DONT_CACHE} specifies that loaded resource bundles are not
 46.2633 +         * put in the cache. {@link #TTL_NO_EXPIRATION_CONTROL} specifies
 46.2634 +         * that loaded resource bundles are put in the cache with no
 46.2635 +         * expiration control.
 46.2636 +         *
 46.2637 +         * <p>The expiration affects only the bundle loading process by the
 46.2638 +         * <code>ResourceBundle.getBundle</code> factory method.  That is,
 46.2639 +         * if the factory method finds a resource bundle in the cache that
 46.2640 +         * has expired, the factory method calls the {@link
 46.2641 +         * #needsReload(String, Locale, String, ClassLoader, ResourceBundle,
 46.2642 +         * long) needsReload} method to determine whether the resource
 46.2643 +         * bundle needs to be reloaded. If <code>needsReload</code> returns
 46.2644 +         * <code>true</code>, the cached resource bundle instance is removed
 46.2645 +         * from the cache. Otherwise, the instance stays in the cache,
 46.2646 +         * updated with the new TTL value returned by this method.
 46.2647 +         *
 46.2648 +         * <p>All cached resource bundles are subject to removal from the
 46.2649 +         * cache due to memory constraints of the runtime environment.
 46.2650 +         * Returning a large positive value doesn't mean to lock loaded
 46.2651 +         * resource bundles in the cache.
 46.2652 +         *
 46.2653 +         * <p>The default implementation returns {@link #TTL_NO_EXPIRATION_CONTROL}.
 46.2654 +         *
 46.2655 +         * @param baseName
 46.2656 +         *        the base name of the resource bundle for which the
 46.2657 +         *        expiration value is specified.
 46.2658 +         * @param locale
 46.2659 +         *        the locale of the resource bundle for which the
 46.2660 +         *        expiration value is specified.
 46.2661 +         * @return the time (0 or a positive millisecond offset from the
 46.2662 +         *        cached time) to get loaded bundles expired in the cache,
 46.2663 +         *        {@link #TTL_NO_EXPIRATION_CONTROL} to disable the
 46.2664 +         *        expiration control, or {@link #TTL_DONT_CACHE} to disable
 46.2665 +         *        caching.
 46.2666 +         * @exception NullPointerException
 46.2667 +         *        if <code>baseName</code> or <code>locale</code> is
 46.2668 +         *        <code>null</code>
 46.2669 +         */
 46.2670 +        public long getTimeToLive(String baseName, Locale locale) {
 46.2671 +            if (baseName == null || locale == null) {
 46.2672 +                throw new NullPointerException();
 46.2673 +            }
 46.2674 +            return TTL_NO_EXPIRATION_CONTROL;
 46.2675 +        }
 46.2676 +
 46.2677 +        /**
 46.2678 +         * Determines if the expired <code>bundle</code> in the cache needs
 46.2679 +         * to be reloaded based on the loading time given by
 46.2680 +         * <code>loadTime</code> or some other criteria. The method returns
 46.2681 +         * <code>true</code> if reloading is required; <code>false</code>
 46.2682 +         * otherwise. <code>loadTime</code> is a millisecond offset since
 46.2683 +         * the <a href="Calendar.html#Epoch"> <code>Calendar</code>
 46.2684 +         * Epoch</a>.
 46.2685 +         *
 46.2686 +         * The calling <code>ResourceBundle.getBundle</code> factory method
 46.2687 +         * calls this method on the <code>ResourceBundle.Control</code>
 46.2688 +         * instance used for its current invocation, not on the instance
 46.2689 +         * used in the invocation that originally loaded the resource
 46.2690 +         * bundle.
 46.2691 +         *
 46.2692 +         * <p>The default implementation compares <code>loadTime</code> and
 46.2693 +         * the last modified time of the source data of the resource
 46.2694 +         * bundle. If it's determined that the source data has been modified
 46.2695 +         * since <code>loadTime</code>, <code>true</code> is
 46.2696 +         * returned. Otherwise, <code>false</code> is returned. This
 46.2697 +         * implementation assumes that the given <code>format</code> is the
 46.2698 +         * same string as its file suffix if it's not one of the default
 46.2699 +         * formats, <code>"java.class"</code> or
 46.2700 +         * <code>"java.properties"</code>.
 46.2701 +         *
 46.2702 +         * @param baseName
 46.2703 +         *        the base bundle name of the resource bundle, a
 46.2704 +         *        fully qualified class name
 46.2705 +         * @param locale
 46.2706 +         *        the locale for which the resource bundle
 46.2707 +         *        should be instantiated
 46.2708 +         * @param format
 46.2709 +         *        the resource bundle format to be loaded
 46.2710 +         * @param loader
 46.2711 +         *        the <code>ClassLoader</code> to use to load the bundle
 46.2712 +         * @param bundle
 46.2713 +         *        the resource bundle instance that has been expired
 46.2714 +         *        in the cache
 46.2715 +         * @param loadTime
 46.2716 +         *        the time when <code>bundle</code> was loaded and put
 46.2717 +         *        in the cache
 46.2718 +         * @return <code>true</code> if the expired bundle needs to be
 46.2719 +         *        reloaded; <code>false</code> otherwise.
 46.2720 +         * @exception NullPointerException
 46.2721 +         *        if <code>baseName</code>, <code>locale</code>,
 46.2722 +         *        <code>format</code>, <code>loader</code>, or
 46.2723 +         *        <code>bundle</code> is <code>null</code>
 46.2724 +         */
 46.2725 +        public boolean needsReload(String baseName, Locale locale,
 46.2726 +                                   String format, ClassLoader loader,
 46.2727 +                                   ResourceBundle bundle, long loadTime) {
 46.2728 +            if (bundle == null) {
 46.2729 +                throw new NullPointerException();
 46.2730 +            }
 46.2731 +            if (format.equals("java.class") || format.equals("java.properties")) {
 46.2732 +                format = format.substring(5);
 46.2733 +            }
 46.2734 +            boolean result = false;
 46.2735 +            try {
 46.2736 +                String resourceName = toResourceName(toBundleName(baseName, locale), format);
 46.2737 +                URL url = loader.getResource(resourceName);
 46.2738 +                if (url != null) {
 46.2739 +                    long lastModified = 0;
 46.2740 +                    URLConnection connection = url.openConnection();
 46.2741 +                    if (connection != null) {
 46.2742 +                        // disable caches to get the correct data
 46.2743 +                        connection.setUseCaches(false);
 46.2744 +                        if (connection instanceof JarURLConnection) {
 46.2745 +                            JarEntry ent = ((JarURLConnection)connection).getJarEntry();
 46.2746 +                            if (ent != null) {
 46.2747 +                                lastModified = ent.getTime();
 46.2748 +                                if (lastModified == -1) {
 46.2749 +                                    lastModified = 0;
 46.2750 +                                }
 46.2751 +                            }
 46.2752 +                        } else {
 46.2753 +                            lastModified = connection.getLastModified();
 46.2754 +                        }
 46.2755 +                    }
 46.2756 +                    result = lastModified >= loadTime;
 46.2757 +                }
 46.2758 +            } catch (NullPointerException npe) {
 46.2759 +                throw npe;
 46.2760 +            } catch (Exception e) {
 46.2761 +                // ignore other exceptions
 46.2762 +            }
 46.2763 +            return result;
 46.2764 +        }
 46.2765 +
 46.2766 +        /**
 46.2767 +         * Converts the given <code>baseName</code> and <code>locale</code>
 46.2768 +         * to the bundle name. This method is called from the default
 46.2769 +         * implementation of the {@link #newBundle(String, Locale, String,
 46.2770 +         * ClassLoader, boolean) newBundle} and {@link #needsReload(String,
 46.2771 +         * Locale, String, ClassLoader, ResourceBundle, long) needsReload}
 46.2772 +         * methods.
 46.2773 +         *
 46.2774 +         * <p>This implementation returns the following value:
 46.2775 +         * <pre>
 46.2776 +         *     baseName + "_" + language + "_" + script + "_" + country + "_" + variant
 46.2777 +         * </pre>
 46.2778 +         * where <code>language</code>, <code>script</code>, <code>country</code>,
 46.2779 +         * and <code>variant</code> are the language, script, country, and variant
 46.2780 +         * values of <code>locale</code>, respectively. Final component values that
 46.2781 +         * are empty Strings are omitted along with the preceding '_'.  When the
 46.2782 +         * script is empty, the script value is ommitted along with the preceding '_'.
 46.2783 +         * If all of the values are empty strings, then <code>baseName</code>
 46.2784 +         * is returned.
 46.2785 +         *
 46.2786 +         * <p>For example, if <code>baseName</code> is
 46.2787 +         * <code>"baseName"</code> and <code>locale</code> is
 46.2788 +         * <code>Locale("ja",&nbsp;"",&nbsp;"XX")</code>, then
 46.2789 +         * <code>"baseName_ja_&thinsp;_XX"</code> is returned. If the given
 46.2790 +         * locale is <code>Locale("en")</code>, then
 46.2791 +         * <code>"baseName_en"</code> is returned.
 46.2792 +         *
 46.2793 +         * <p>Overriding this method allows applications to use different
 46.2794 +         * conventions in the organization and packaging of localized
 46.2795 +         * resources.
 46.2796 +         *
 46.2797 +         * @param baseName
 46.2798 +         *        the base name of the resource bundle, a fully
 46.2799 +         *        qualified class name
 46.2800 +         * @param locale
 46.2801 +         *        the locale for which a resource bundle should be
 46.2802 +         *        loaded
 46.2803 +         * @return the bundle name for the resource bundle
 46.2804 +         * @exception NullPointerException
 46.2805 +         *        if <code>baseName</code> or <code>locale</code>
 46.2806 +         *        is <code>null</code>
 46.2807 +         */
 46.2808 +        public String toBundleName(String baseName, Locale locale) {
 46.2809 +            if (locale == Locale.ROOT) {
 46.2810 +                return baseName;
 46.2811 +            }
 46.2812 +
 46.2813 +            String language = locale.getLanguage();
 46.2814 +            String script = locale.getScript();
 46.2815 +            String country = locale.getCountry();
 46.2816 +            String variant = locale.getVariant();
 46.2817 +
 46.2818 +            if (language == "" && country == "" && variant == "") {
 46.2819 +                return baseName;
 46.2820 +            }
 46.2821 +
 46.2822 +            StringBuilder sb = new StringBuilder(baseName);
 46.2823 +            sb.append('_');
 46.2824 +            if (script != "") {
 46.2825 +                if (variant != "") {
 46.2826 +                    sb.append(language).append('_').append(script).append('_').append(country).append('_').append(variant);
 46.2827 +                } else if (country != "") {
 46.2828 +                    sb.append(language).append('_').append(script).append('_').append(country);
 46.2829 +                } else {
 46.2830 +                    sb.append(language).append('_').append(script);
 46.2831 +                }
 46.2832 +            } else {
 46.2833 +                if (variant != "") {
 46.2834 +                    sb.append(language).append('_').append(country).append('_').append(variant);
 46.2835 +                } else if (country != "") {
 46.2836 +                    sb.append(language).append('_').append(country);
 46.2837 +                } else {
 46.2838 +                    sb.append(language);
 46.2839 +                }
 46.2840 +            }
 46.2841 +            return sb.toString();
 46.2842 +
 46.2843 +        }
 46.2844 +
 46.2845 +        /**
 46.2846 +         * Converts the given <code>bundleName</code> to the form required
 46.2847 +         * by the {@link ClassLoader#getResource ClassLoader.getResource}
 46.2848 +         * method by replacing all occurrences of <code>'.'</code> in
 46.2849 +         * <code>bundleName</code> with <code>'/'</code> and appending a
 46.2850 +         * <code>'.'</code> and the given file <code>suffix</code>. For
 46.2851 +         * example, if <code>bundleName</code> is
 46.2852 +         * <code>"foo.bar.MyResources_ja_JP"</code> and <code>suffix</code>
 46.2853 +         * is <code>"properties"</code>, then
 46.2854 +         * <code>"foo/bar/MyResources_ja_JP.properties"</code> is returned.
 46.2855 +         *
 46.2856 +         * @param bundleName
 46.2857 +         *        the bundle name
 46.2858 +         * @param suffix
 46.2859 +         *        the file type suffix
 46.2860 +         * @return the converted resource name
 46.2861 +         * @exception NullPointerException
 46.2862 +         *         if <code>bundleName</code> or <code>suffix</code>
 46.2863 +         *         is <code>null</code>
 46.2864 +         */
 46.2865 +        public final String toResourceName(String bundleName, String suffix) {
 46.2866 +            StringBuilder sb = new StringBuilder(bundleName.length() + 1 + suffix.length());
 46.2867 +            sb.append(bundleName.replace('.', '/')).append('.').append(suffix);
 46.2868 +            return sb.toString();
 46.2869 +        }
 46.2870 +    }
 46.2871 +
 46.2872 +    private static class SingleFormatControl extends Control {
 46.2873 +        private static final Control PROPERTIES_ONLY
 46.2874 +            = new SingleFormatControl(FORMAT_PROPERTIES);
 46.2875 +
 46.2876 +        private static final Control CLASS_ONLY
 46.2877 +            = new SingleFormatControl(FORMAT_CLASS);
 46.2878 +
 46.2879 +        private final List<String> formats;
 46.2880 +
 46.2881 +        protected SingleFormatControl(List<String> formats) {
 46.2882 +            this.formats = formats;
 46.2883 +        }
 46.2884 +
 46.2885 +        public List<String> getFormats(String baseName) {
 46.2886 +            if (baseName == null) {
 46.2887 +                throw new NullPointerException();
 46.2888 +            }
 46.2889 +            return formats;
 46.2890 +        }
 46.2891 +    }
 46.2892 +
 46.2893 +    private static final class NoFallbackControl extends SingleFormatControl {
 46.2894 +        private static final Control NO_FALLBACK
 46.2895 +            = new NoFallbackControl(FORMAT_DEFAULT);
 46.2896 +
 46.2897 +        private static final Control PROPERTIES_ONLY_NO_FALLBACK
 46.2898 +            = new NoFallbackControl(FORMAT_PROPERTIES);
 46.2899 +
 46.2900 +        private static final Control CLASS_ONLY_NO_FALLBACK
 46.2901 +            = new NoFallbackControl(FORMAT_CLASS);
 46.2902 +
 46.2903 +        protected NoFallbackControl(List<String> formats) {
 46.2904 +            super(formats);
 46.2905 +        }
 46.2906 +
 46.2907 +        public Locale getFallbackLocale(String baseName, Locale locale) {
 46.2908 +            if (baseName == null || locale == null) {
 46.2909 +                throw new NullPointerException();
 46.2910 +            }
 46.2911 +            return null;
 46.2912 +        }
 46.2913 +    }
 46.2914 +}
    47.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    47.2 +++ b/rt/emul/compact/src/main/java/java/util/SimpleTimeZone.java	Thu Oct 03 15:40:35 2013 +0200
    47.3 @@ -0,0 +1,1706 @@
    47.4 +/*
    47.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    47.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    47.7 + *
    47.8 + * This code is free software; you can redistribute it and/or modify it
    47.9 + * under the terms of the GNU General Public License version 2 only, as
   47.10 + * published by the Free Software Foundation.  Oracle designates this
   47.11 + * particular file as subject to the "Classpath" exception as provided
   47.12 + * by Oracle in the LICENSE file that accompanied this code.
   47.13 + *
   47.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   47.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   47.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   47.17 + * version 2 for more details (a copy is included in the LICENSE file that
   47.18 + * accompanied this code).
   47.19 + *
   47.20 + * You should have received a copy of the GNU General Public License version
   47.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   47.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   47.23 + *
   47.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   47.25 + * or visit www.oracle.com if you need additional information or have any
   47.26 + * questions.
   47.27 + */
   47.28 +
   47.29 +/*
   47.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   47.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   47.32 + *
   47.33 + *   The original version of this source code and documentation is copyrighted
   47.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   47.35 + * materials are provided under terms of a License Agreement between Taligent
   47.36 + * and Sun. This technology is protected by multiple US and International
   47.37 + * patents. This notice and attribution to Taligent may not be removed.
   47.38 + *   Taligent is a registered trademark of Taligent, Inc.
   47.39 + *
   47.40 + */
   47.41 +
   47.42 +package java.util;
   47.43 +
   47.44 +import java.io.ObjectInputStream;
   47.45 +import java.io.ObjectOutputStream;
   47.46 +import java.io.IOException;
   47.47 +import sun.util.calendar.CalendarSystem;
   47.48 +import sun.util.calendar.CalendarUtils;
   47.49 +import sun.util.calendar.BaseCalendar;
   47.50 +import sun.util.calendar.Gregorian;
   47.51 +
   47.52 +/**
   47.53 + * <code>SimpleTimeZone</code> is a concrete subclass of <code>TimeZone</code>
   47.54 + * that represents a time zone for use with a Gregorian calendar.
   47.55 + * The class holds an offset from GMT, called <em>raw offset</em>, and start
   47.56 + * and end rules for a daylight saving time schedule.  Since it only holds
   47.57 + * single values for each, it cannot handle historical changes in the offset
   47.58 + * from GMT and the daylight saving schedule, except that the {@link
   47.59 + * #setStartYear setStartYear} method can specify the year when the daylight
   47.60 + * saving time schedule starts in effect.
   47.61 + * <p>
   47.62 + * To construct a <code>SimpleTimeZone</code> with a daylight saving time
   47.63 + * schedule, the schedule can be described with a set of rules,
   47.64 + * <em>start-rule</em> and <em>end-rule</em>. A day when daylight saving time
   47.65 + * starts or ends is specified by a combination of <em>month</em>,
   47.66 + * <em>day-of-month</em>, and <em>day-of-week</em> values. The <em>month</em>
   47.67 + * value is represented by a Calendar {@link Calendar#MONTH MONTH} field
   47.68 + * value, such as {@link Calendar#MARCH}. The <em>day-of-week</em> value is
   47.69 + * represented by a Calendar {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value,
   47.70 + * such as {@link Calendar#SUNDAY SUNDAY}. The meanings of value combinations
   47.71 + * are as follows.
   47.72 + *
   47.73 + * <ul>
   47.74 + * <li><b>Exact day of month</b><br>
   47.75 + * To specify an exact day of month, set the <em>month</em> and
   47.76 + * <em>day-of-month</em> to an exact value, and <em>day-of-week</em> to zero. For
   47.77 + * example, to specify March 1, set the <em>month</em> to {@link Calendar#MARCH
   47.78 + * MARCH}, <em>day-of-month</em> to 1, and <em>day-of-week</em> to 0.</li>
   47.79 + *
   47.80 + * <li><b>Day of week on or after day of month</b><br>
   47.81 + * To specify a day of week on or after an exact day of month, set the
   47.82 + * <em>month</em> to an exact month value, <em>day-of-month</em> to the day on
   47.83 + * or after which the rule is applied, and <em>day-of-week</em> to a negative {@link
   47.84 + * Calendar#DAY_OF_WEEK DAY_OF_WEEK} field value. For example, to specify the
   47.85 + * second Sunday of April, set <em>month</em> to {@link Calendar#APRIL APRIL},
   47.86 + * <em>day-of-month</em> to 8, and <em>day-of-week</em> to <code>-</code>{@link
   47.87 + * Calendar#SUNDAY SUNDAY}.</li>
   47.88 + *
   47.89 + * <li><b>Day of week on or before day of month</b><br>
   47.90 + * To specify a day of the week on or before an exact day of the month, set
   47.91 + * <em>day-of-month</em> and <em>day-of-week</em> to a negative value. For
   47.92 + * example, to specify the last Wednesday on or before the 21st of March, set
   47.93 + * <em>month</em> to {@link Calendar#MARCH MARCH}, <em>day-of-month</em> is -21
   47.94 + * and <em>day-of-week</em> is <code>-</code>{@link Calendar#WEDNESDAY WEDNESDAY}. </li>
   47.95 + *
   47.96 + * <li><b>Last day-of-week of month</b><br>
   47.97 + * To specify, the last day-of-week of the month, set <em>day-of-week</em> to a
   47.98 + * {@link Calendar#DAY_OF_WEEK DAY_OF_WEEK} value and <em>day-of-month</em> to
   47.99 + * -1. For example, to specify the last Sunday of October, set <em>month</em>
  47.100 + * to {@link Calendar#OCTOBER OCTOBER}, <em>day-of-week</em> to {@link
  47.101 + * Calendar#SUNDAY SUNDAY} and <em>day-of-month</em> to -1.  </li>
  47.102 + *
  47.103 + * </ul>
  47.104 + * The time of the day at which daylight saving time starts or ends is
  47.105 + * specified by a millisecond value within the day. There are three kinds of
  47.106 + * <em>mode</em>s to specify the time: {@link #WALL_TIME}, {@link
  47.107 + * #STANDARD_TIME} and {@link #UTC_TIME}. For example, if daylight
  47.108 + * saving time ends
  47.109 + * at 2:00 am in the wall clock time, it can be specified by 7200000
  47.110 + * milliseconds in the {@link #WALL_TIME} mode. In this case, the wall clock time
  47.111 + * for an <em>end-rule</em> means the same thing as the daylight time.
  47.112 + * <p>
  47.113 + * The following are examples of parameters for constructing time zone objects.
  47.114 + * <pre><code>
  47.115 + *      // Base GMT offset: -8:00
  47.116 + *      // DST starts:      at 2:00am in standard time
  47.117 + *      //                  on the first Sunday in April
  47.118 + *      // DST ends:        at 2:00am in daylight time
  47.119 + *      //                  on the last Sunday in October
  47.120 + *      // Save:            1 hour
  47.121 + *      SimpleTimeZone(-28800000,
  47.122 + *                     "America/Los_Angeles",
  47.123 + *                     Calendar.APRIL, 1, -Calendar.SUNDAY,
  47.124 + *                     7200000,
  47.125 + *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
  47.126 + *                     7200000,
  47.127 + *                     3600000)
  47.128 + *
  47.129 + *      // Base GMT offset: +1:00
  47.130 + *      // DST starts:      at 1:00am in UTC time
  47.131 + *      //                  on the last Sunday in March
  47.132 + *      // DST ends:        at 1:00am in UTC time
  47.133 + *      //                  on the last Sunday in October
  47.134 + *      // Save:            1 hour
  47.135 + *      SimpleTimeZone(3600000,
  47.136 + *                     "Europe/Paris",
  47.137 + *                     Calendar.MARCH, -1, Calendar.SUNDAY,
  47.138 + *                     3600000, SimpleTimeZone.UTC_TIME,
  47.139 + *                     Calendar.OCTOBER, -1, Calendar.SUNDAY,
  47.140 + *                     3600000, SimpleTimeZone.UTC_TIME,
  47.141 + *                     3600000)
  47.142 + * </code></pre>
  47.143 + * These parameter rules are also applicable to the set rule methods, such as
  47.144 + * <code>setStartRule</code>.
  47.145 + *
  47.146 + * @since 1.1
  47.147 + * @see      Calendar
  47.148 + * @see      GregorianCalendar
  47.149 + * @see      TimeZone
  47.150 + * @author   David Goldsmith, Mark Davis, Chen-Lieh Huang, Alan Liu
  47.151 + */
  47.152 +
  47.153 +public class SimpleTimeZone extends TimeZone {
  47.154 +    /**
  47.155 +     * Constructs a SimpleTimeZone with the given base time zone offset from GMT
  47.156 +     * and time zone ID with no daylight saving time schedule.
  47.157 +     *
  47.158 +     * @param rawOffset  The base time zone offset in milliseconds to GMT.
  47.159 +     * @param ID         The time zone name that is given to this instance.
  47.160 +     */
  47.161 +    public SimpleTimeZone(int rawOffset, String ID)
  47.162 +    {
  47.163 +        this.rawOffset = rawOffset;
  47.164 +        setID (ID);
  47.165 +        dstSavings = millisPerHour; // In case user sets rules later
  47.166 +    }
  47.167 +
  47.168 +    /**
  47.169 +     * Constructs a SimpleTimeZone with the given base time zone offset from
  47.170 +     * GMT, time zone ID, and rules for starting and ending the daylight
  47.171 +     * time.
  47.172 +     * Both <code>startTime</code> and <code>endTime</code> are specified to be
  47.173 +     * represented in the wall clock time. The amount of daylight saving is
  47.174 +     * assumed to be 3600000 milliseconds (i.e., one hour). This constructor is
  47.175 +     * equivalent to:
  47.176 +     * <pre><code>
  47.177 +     *     SimpleTimeZone(rawOffset,
  47.178 +     *                    ID,
  47.179 +     *                    startMonth,
  47.180 +     *                    startDay,
  47.181 +     *                    startDayOfWeek,
  47.182 +     *                    startTime,
  47.183 +     *                    SimpleTimeZone.{@link #WALL_TIME},
  47.184 +     *                    endMonth,
  47.185 +     *                    endDay,
  47.186 +     *                    endDayOfWeek,
  47.187 +     *                    endTime,
  47.188 +     *                    SimpleTimeZone.{@link #WALL_TIME},
  47.189 +     *                    3600000)
  47.190 +     * </code></pre>
  47.191 +     *
  47.192 +     * @param rawOffset       The given base time zone offset from GMT.
  47.193 +     * @param ID              The time zone ID which is given to this object.
  47.194 +     * @param startMonth      The daylight saving time starting month. Month is
  47.195 +     *                        a {@link Calendar#MONTH MONTH} field value (0-based. e.g., 0
  47.196 +     *                        for January).
  47.197 +     * @param startDay        The day of the month on which the daylight saving time starts.
  47.198 +     *                        See the class description for the special cases of this parameter.
  47.199 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
  47.200 +     *                        See the class description for the special cases of this parameter.
  47.201 +     * @param startTime       The daylight saving time starting time in local wall clock
  47.202 +     *                        time (in milliseconds within the day), which is local
  47.203 +     *                        standard time in this case.
  47.204 +     * @param endMonth        The daylight saving time ending month. Month is
  47.205 +     *                        a {@link Calendar#MONTH MONTH} field
  47.206 +     *                        value (0-based. e.g., 9 for October).
  47.207 +     * @param endDay          The day of the month on which the daylight saving time ends.
  47.208 +     *                        See the class description for the special cases of this parameter.
  47.209 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
  47.210 +     *                        See the class description for the special cases of this parameter.
  47.211 +     * @param endTime         The daylight saving ending time in local wall clock time,
  47.212 +     *                        (in milliseconds within the day) which is local daylight
  47.213 +     *                        time in this case.
  47.214 +     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
  47.215 +     * parameters are out of range for the start or end rule
  47.216 +     */
  47.217 +    public SimpleTimeZone(int rawOffset, String ID,
  47.218 +                          int startMonth, int startDay, int startDayOfWeek, int startTime,
  47.219 +                          int endMonth, int endDay, int endDayOfWeek, int endTime)
  47.220 +    {
  47.221 +        this(rawOffset, ID,
  47.222 +             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
  47.223 +             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
  47.224 +             millisPerHour);
  47.225 +    }
  47.226 +
  47.227 +    /**
  47.228 +     * Constructs a SimpleTimeZone with the given base time zone offset from
  47.229 +     * GMT, time zone ID, and rules for starting and ending the daylight
  47.230 +     * time.
  47.231 +     * Both <code>startTime</code> and <code>endTime</code> are assumed to be
  47.232 +     * represented in the wall clock time. This constructor is equivalent to:
  47.233 +     * <pre><code>
  47.234 +     *     SimpleTimeZone(rawOffset,
  47.235 +     *                    ID,
  47.236 +     *                    startMonth,
  47.237 +     *                    startDay,
  47.238 +     *                    startDayOfWeek,
  47.239 +     *                    startTime,
  47.240 +     *                    SimpleTimeZone.{@link #WALL_TIME},
  47.241 +     *                    endMonth,
  47.242 +     *                    endDay,
  47.243 +     *                    endDayOfWeek,
  47.244 +     *                    endTime,
  47.245 +     *                    SimpleTimeZone.{@link #WALL_TIME},
  47.246 +     *                    dstSavings)
  47.247 +     * </code></pre>
  47.248 +     *
  47.249 +     * @param rawOffset       The given base time zone offset from GMT.
  47.250 +     * @param ID              The time zone ID which is given to this object.
  47.251 +     * @param startMonth      The daylight saving time starting month. Month is
  47.252 +     *                        a {@link Calendar#MONTH MONTH} field
  47.253 +     *                        value (0-based. e.g., 0 for January).
  47.254 +     * @param startDay        The day of the month on which the daylight saving time starts.
  47.255 +     *                        See the class description for the special cases of this parameter.
  47.256 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
  47.257 +     *                        See the class description for the special cases of this parameter.
  47.258 +     * @param startTime       The daylight saving time starting time in local wall clock
  47.259 +     *                        time, which is local standard time in this case.
  47.260 +     * @param endMonth        The daylight saving time ending month. Month is
  47.261 +     *                        a {@link Calendar#MONTH MONTH} field
  47.262 +     *                        value (0-based. e.g., 9 for October).
  47.263 +     * @param endDay          The day of the month on which the daylight saving time ends.
  47.264 +     *                        See the class description for the special cases of this parameter.
  47.265 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
  47.266 +     *                        See the class description for the special cases of this parameter.
  47.267 +     * @param endTime         The daylight saving ending time in local wall clock time,
  47.268 +     *                        which is local daylight time in this case.
  47.269 +     * @param dstSavings      The amount of time in milliseconds saved during
  47.270 +     *                        daylight saving time.
  47.271 +     * @exception IllegalArgumentException if the month, day, dayOfWeek, or time
  47.272 +     * parameters are out of range for the start or end rule
  47.273 +     * @since 1.2
  47.274 +     */
  47.275 +    public SimpleTimeZone(int rawOffset, String ID,
  47.276 +                          int startMonth, int startDay, int startDayOfWeek, int startTime,
  47.277 +                          int endMonth, int endDay, int endDayOfWeek, int endTime,
  47.278 +                          int dstSavings)
  47.279 +    {
  47.280 +        this(rawOffset, ID,
  47.281 +             startMonth, startDay, startDayOfWeek, startTime, WALL_TIME,
  47.282 +             endMonth, endDay, endDayOfWeek, endTime, WALL_TIME,
  47.283 +             dstSavings);
  47.284 +    }
  47.285 +
  47.286 +    /**
  47.287 +     * Constructs a SimpleTimeZone with the given base time zone offset from
  47.288 +     * GMT, time zone ID, and rules for starting and ending the daylight
  47.289 +     * time.
  47.290 +     * This constructor takes the full set of the start and end rules
  47.291 +     * parameters, including modes of <code>startTime</code> and
  47.292 +     * <code>endTime</code>. The mode specifies either {@link #WALL_TIME wall
  47.293 +     * time} or {@link #STANDARD_TIME standard time} or {@link #UTC_TIME UTC
  47.294 +     * time}.
  47.295 +     *
  47.296 +     * @param rawOffset       The given base time zone offset from GMT.
  47.297 +     * @param ID              The time zone ID which is given to this object.
  47.298 +     * @param startMonth      The daylight saving time starting month. Month is
  47.299 +     *                        a {@link Calendar#MONTH MONTH} field
  47.300 +     *                        value (0-based. e.g., 0 for January).
  47.301 +     * @param startDay        The day of the month on which the daylight saving time starts.
  47.302 +     *                        See the class description for the special cases of this parameter.
  47.303 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
  47.304 +     *                        See the class description for the special cases of this parameter.
  47.305 +     * @param startTime       The daylight saving time starting time in the time mode
  47.306 +     *                        specified by <code>startTimeMode</code>.
  47.307 +     * @param startTimeMode   The mode of the start time specified by startTime.
  47.308 +     * @param endMonth        The daylight saving time ending month. Month is
  47.309 +     *                        a {@link Calendar#MONTH MONTH} field
  47.310 +     *                        value (0-based. e.g., 9 for October).
  47.311 +     * @param endDay          The day of the month on which the daylight saving time ends.
  47.312 +     *                        See the class description for the special cases of this parameter.
  47.313 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
  47.314 +     *                        See the class description for the special cases of this parameter.
  47.315 +     * @param endTime         The daylight saving ending time in time time mode
  47.316 +     *                        specified by <code>endTimeMode</code>.
  47.317 +     * @param endTimeMode     The mode of the end time specified by endTime
  47.318 +     * @param dstSavings      The amount of time in milliseconds saved during
  47.319 +     *                        daylight saving time.
  47.320 +     *
  47.321 +     * @exception IllegalArgumentException if the month, day, dayOfWeek, time more, or
  47.322 +     * time parameters are out of range for the start or end rule, or if a time mode
  47.323 +     * value is invalid.
  47.324 +     *
  47.325 +     * @see #WALL_TIME
  47.326 +     * @see #STANDARD_TIME
  47.327 +     * @see #UTC_TIME
  47.328 +     *
  47.329 +     * @since 1.4
  47.330 +     */
  47.331 +    public SimpleTimeZone(int rawOffset, String ID,
  47.332 +                          int startMonth, int startDay, int startDayOfWeek,
  47.333 +                          int startTime, int startTimeMode,
  47.334 +                          int endMonth, int endDay, int endDayOfWeek,
  47.335 +                          int endTime, int endTimeMode,
  47.336 +                          int dstSavings) {
  47.337 +
  47.338 +        setID(ID);
  47.339 +        this.rawOffset      = rawOffset;
  47.340 +        this.startMonth     = startMonth;
  47.341 +        this.startDay       = startDay;
  47.342 +        this.startDayOfWeek = startDayOfWeek;
  47.343 +        this.startTime      = startTime;
  47.344 +        this.startTimeMode  = startTimeMode;
  47.345 +        this.endMonth       = endMonth;
  47.346 +        this.endDay         = endDay;
  47.347 +        this.endDayOfWeek   = endDayOfWeek;
  47.348 +        this.endTime        = endTime;
  47.349 +        this.endTimeMode    = endTimeMode;
  47.350 +        this.dstSavings     = dstSavings;
  47.351 +
  47.352 +        // this.useDaylight is set by decodeRules
  47.353 +        decodeRules();
  47.354 +        if (dstSavings <= 0) {
  47.355 +            throw new IllegalArgumentException("Illegal daylight saving value: " + dstSavings);
  47.356 +        }
  47.357 +    }
  47.358 +
  47.359 +    /**
  47.360 +     * Sets the daylight saving time starting year.
  47.361 +     *
  47.362 +     * @param year  The daylight saving starting year.
  47.363 +     */
  47.364 +    public void setStartYear(int year)
  47.365 +    {
  47.366 +        startYear = year;
  47.367 +        invalidateCache();
  47.368 +    }
  47.369 +
  47.370 +    /**
  47.371 +     * Sets the daylight saving time start rule. For example, if daylight saving
  47.372 +     * time starts on the first Sunday in April at 2 am in local wall clock
  47.373 +     * time, you can set the start rule by calling:
  47.374 +     * <pre><code>setStartRule(Calendar.APRIL, 1, Calendar.SUNDAY, 2*60*60*1000);</code></pre>
  47.375 +     *
  47.376 +     * @param startMonth      The daylight saving time starting month. Month is
  47.377 +     *                        a {@link Calendar#MONTH MONTH} field
  47.378 +     *                        value (0-based. e.g., 0 for January).
  47.379 +     * @param startDay        The day of the month on which the daylight saving time starts.
  47.380 +     *                        See the class description for the special cases of this parameter.
  47.381 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
  47.382 +     *                        See the class description for the special cases of this parameter.
  47.383 +     * @param startTime       The daylight saving time starting time in local wall clock
  47.384 +     *                        time, which is local standard time in this case.
  47.385 +     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
  47.386 +     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
  47.387 +     */
  47.388 +    public void setStartRule(int startMonth, int startDay, int startDayOfWeek, int startTime)
  47.389 +    {
  47.390 +        this.startMonth = startMonth;
  47.391 +        this.startDay = startDay;
  47.392 +        this.startDayOfWeek = startDayOfWeek;
  47.393 +        this.startTime = startTime;
  47.394 +        startTimeMode = WALL_TIME;
  47.395 +        decodeStartRule();
  47.396 +        invalidateCache();
  47.397 +    }
  47.398 +
  47.399 +    /**
  47.400 +     * Sets the daylight saving time start rule to a fixed date within a month.
  47.401 +     * This method is equivalent to:
  47.402 +     * <pre><code>setStartRule(startMonth, startDay, 0, startTime)</code></pre>
  47.403 +     *
  47.404 +     * @param startMonth      The daylight saving time starting month. Month is
  47.405 +     *                        a {@link Calendar#MONTH MONTH} field
  47.406 +     *                        value (0-based. e.g., 0 for January).
  47.407 +     * @param startDay        The day of the month on which the daylight saving time starts.
  47.408 +     * @param startTime       The daylight saving time starting time in local wall clock
  47.409 +     *                        time, which is local standard time in this case.
  47.410 +     *                        See the class description for the special cases of this parameter.
  47.411 +     * @exception IllegalArgumentException if the <code>startMonth</code>,
  47.412 +     * <code>startDayOfMonth</code>, or <code>startTime</code> parameters are out of range
  47.413 +     * @since 1.2
  47.414 +     */
  47.415 +    public void setStartRule(int startMonth, int startDay, int startTime) {
  47.416 +        setStartRule(startMonth, startDay, 0, startTime);
  47.417 +    }
  47.418 +
  47.419 +    /**
  47.420 +     * Sets the daylight saving time start rule to a weekday before or after the given date within
  47.421 +     * a month, e.g., the first Monday on or after the 8th.
  47.422 +     *
  47.423 +     * @param startMonth      The daylight saving time starting month. Month is
  47.424 +     *                        a {@link Calendar#MONTH MONTH} field
  47.425 +     *                        value (0-based. e.g., 0 for January).
  47.426 +     * @param startDay        The day of the month on which the daylight saving time starts.
  47.427 +     * @param startDayOfWeek  The daylight saving time starting day-of-week.
  47.428 +     * @param startTime       The daylight saving time starting time in local wall clock
  47.429 +     *                        time, which is local standard time in this case.
  47.430 +     * @param after           If true, this rule selects the first <code>dayOfWeek</code> on or
  47.431 +     *                        <em>after</em> <code>dayOfMonth</code>.  If false, this rule
  47.432 +     *                        selects the last <code>dayOfWeek</code> on or <em>before</em>
  47.433 +     *                        <code>dayOfMonth</code>.
  47.434 +     * @exception IllegalArgumentException if the <code>startMonth</code>, <code>startDay</code>,
  47.435 +     * <code>startDayOfWeek</code>, or <code>startTime</code> parameters are out of range
  47.436 +     * @since 1.2
  47.437 +     */
  47.438 +    public void setStartRule(int startMonth, int startDay, int startDayOfWeek,
  47.439 +                             int startTime, boolean after)
  47.440 +    {
  47.441 +        // TODO: this method doesn't check the initial values of dayOfMonth or dayOfWeek.
  47.442 +        if (after) {
  47.443 +            setStartRule(startMonth, startDay, -startDayOfWeek, startTime);
  47.444 +        } else {
  47.445 +            setStartRule(startMonth, -startDay, -startDayOfWeek, startTime);
  47.446 +        }
  47.447 +    }
  47.448 +
  47.449 +    /**
  47.450 +     * Sets the daylight saving time end rule. For example, if daylight saving time
  47.451 +     * ends on the last Sunday in October at 2 am in wall clock time,
  47.452 +     * you can set the end rule by calling:
  47.453 +     * <code>setEndRule(Calendar.OCTOBER, -1, Calendar.SUNDAY, 2*60*60*1000);</code>
  47.454 +     *
  47.455 +     * @param endMonth        The daylight saving time ending month. Month is
  47.456 +     *                        a {@link Calendar#MONTH MONTH} field
  47.457 +     *                        value (0-based. e.g., 9 for October).
  47.458 +     * @param endDay          The day of the month on which the daylight saving time ends.
  47.459 +     *                        See the class description for the special cases of this parameter.
  47.460 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
  47.461 +     *                        See the class description for the special cases of this parameter.
  47.462 +     * @param endTime         The daylight saving ending time in local wall clock time,
  47.463 +     *                        (in milliseconds within the day) which is local daylight
  47.464 +     *                        time in this case.
  47.465 +     * @exception IllegalArgumentException if the <code>endMonth</code>, <code>endDay</code>,
  47.466 +     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
  47.467 +     */
  47.468 +    public void setEndRule(int endMonth, int endDay, int endDayOfWeek,
  47.469 +                           int endTime)
  47.470 +    {
  47.471 +        this.endMonth = endMonth;
  47.472 +        this.endDay = endDay;
  47.473 +        this.endDayOfWeek = endDayOfWeek;
  47.474 +        this.endTime = endTime;
  47.475 +        this.endTimeMode = WALL_TIME;
  47.476 +        decodeEndRule();
  47.477 +        invalidateCache();
  47.478 +    }
  47.479 +
  47.480 +    /**
  47.481 +     * Sets the daylight saving time end rule to a fixed date within a month.
  47.482 +     * This method is equivalent to:
  47.483 +     * <pre><code>setEndRule(endMonth, endDay, 0, endTime)</code></pre>
  47.484 +     *
  47.485 +     * @param endMonth        The daylight saving time ending month. Month is
  47.486 +     *                        a {@link Calendar#MONTH MONTH} field
  47.487 +     *                        value (0-based. e.g., 9 for October).
  47.488 +     * @param endDay          The day of the month on which the daylight saving time ends.
  47.489 +     * @param endTime         The daylight saving ending time in local wall clock time,
  47.490 +     *                        (in milliseconds within the day) which is local daylight
  47.491 +     *                        time in this case.
  47.492 +     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
  47.493 +     * or <code>endTime</code> parameters are out of range
  47.494 +     * @since 1.2
  47.495 +     */
  47.496 +    public void setEndRule(int endMonth, int endDay, int endTime)
  47.497 +    {
  47.498 +        setEndRule(endMonth, endDay, 0, endTime);
  47.499 +    }
  47.500 +
  47.501 +    /**
  47.502 +     * Sets the daylight saving time end rule to a weekday before or after the given date within
  47.503 +     * a month, e.g., the first Monday on or after the 8th.
  47.504 +     *
  47.505 +     * @param endMonth        The daylight saving time ending month. Month is
  47.506 +     *                        a {@link Calendar#MONTH MONTH} field
  47.507 +     *                        value (0-based. e.g., 9 for October).
  47.508 +     * @param endDay          The day of the month on which the daylight saving time ends.
  47.509 +     * @param endDayOfWeek    The daylight saving time ending day-of-week.
  47.510 +     * @param endTime         The daylight saving ending time in local wall clock time,
  47.511 +     *                        (in milliseconds within the day) which is local daylight
  47.512 +     *                        time in this case.
  47.513 +     * @param after           If true, this rule selects the first <code>endDayOfWeek</code> on
  47.514 +     *                        or <em>after</em> <code>endDay</code>.  If false, this rule
  47.515 +     *                        selects the last <code>endDayOfWeek</code> on or before
  47.516 +     *                        <code>endDay</code> of the month.
  47.517 +     * @exception IllegalArgumentException the <code>endMonth</code>, <code>endDay</code>,
  47.518 +     * <code>endDayOfWeek</code>, or <code>endTime</code> parameters are out of range
  47.519 +     * @since 1.2
  47.520 +     */
  47.521 +    public void setEndRule(int endMonth, int endDay, int endDayOfWeek, int endTime, boolean after)
  47.522 +    {
  47.523 +        if (after) {
  47.524 +            setEndRule(endMonth, endDay, -endDayOfWeek, endTime);
  47.525 +        } else {
  47.526 +            setEndRule(endMonth, -endDay, -endDayOfWeek, endTime);
  47.527 +        }
  47.528 +    }
  47.529 +
  47.530 +    /**
  47.531 +     * Returns the offset of this time zone from UTC at the given
  47.532 +     * time. If daylight saving time is in effect at the given time,
  47.533 +     * the offset value is adjusted with the amount of daylight
  47.534 +     * saving.
  47.535 +     *
  47.536 +     * @param date the time at which the time zone offset is found
  47.537 +     * @return the amount of time in milliseconds to add to UTC to get
  47.538 +     * local time.
  47.539 +     * @since 1.4
  47.540 +     */
  47.541 +    public int getOffset(long date) {
  47.542 +        return getOffsets(date, null);
  47.543 +    }
  47.544 +
  47.545 +    /**
  47.546 +     * @see TimeZone#getOffsets
  47.547 +     */
  47.548 +    int getOffsets(long date, int[] offsets) {
  47.549 +        int offset = rawOffset;
  47.550 +
  47.551 +      computeOffset:
  47.552 +        if (useDaylight) {
  47.553 +            synchronized (this) {
  47.554 +                if (cacheStart != 0) {
  47.555 +                    if (date >= cacheStart && date < cacheEnd) {
  47.556 +                        offset += dstSavings;
  47.557 +                        break computeOffset;
  47.558 +                    }
  47.559 +                }
  47.560 +            }
  47.561 +            BaseCalendar cal = date >= GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER ?
  47.562 +                gcal : (BaseCalendar) CalendarSystem.forName("julian");
  47.563 +            BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  47.564 +            // Get the year in local time
  47.565 +            cal.getCalendarDate(date + rawOffset, cdate);
  47.566 +            int year = cdate.getNormalizedYear();
  47.567 +            if (year >= startYear) {
  47.568 +                // Clear time elements for the transition calculations
  47.569 +                cdate.setTimeOfDay(0, 0, 0, 0);
  47.570 +                offset = getOffset(cal, cdate, year, date);
  47.571 +            }
  47.572 +        }
  47.573 +
  47.574 +        if (offsets != null) {
  47.575 +            offsets[0] = rawOffset;
  47.576 +            offsets[1] = offset - rawOffset;
  47.577 +        }
  47.578 +        return offset;
  47.579 +    }
  47.580 +
  47.581 +   /**
  47.582 +     * Returns the difference in milliseconds between local time and
  47.583 +     * UTC, taking into account both the raw offset and the effect of
  47.584 +     * daylight saving, for the specified date and time.  This method
  47.585 +     * assumes that the start and end month are distinct.  It also
  47.586 +     * uses a default {@link GregorianCalendar} object as its
  47.587 +     * underlying calendar, such as for determining leap years.  Do
  47.588 +     * not use the result of this method with a calendar other than a
  47.589 +     * default <code>GregorianCalendar</code>.
  47.590 +     *
  47.591 +     * <p><em>Note:  In general, clients should use
  47.592 +     * <code>Calendar.get(ZONE_OFFSET) + Calendar.get(DST_OFFSET)</code>
  47.593 +     * instead of calling this method.</em>
  47.594 +     *
  47.595 +     * @param era       The era of the given date.
  47.596 +     * @param year      The year in the given date.
  47.597 +     * @param month     The month in the given date. Month is 0-based. e.g.,
  47.598 +     *                  0 for January.
  47.599 +     * @param day       The day-in-month of the given date.
  47.600 +     * @param dayOfWeek The day-of-week of the given date.
  47.601 +     * @param millis    The milliseconds in day in <em>standard</em> local time.
  47.602 +     * @return          The milliseconds to add to UTC to get local time.
  47.603 +     * @exception       IllegalArgumentException the <code>era</code>,
  47.604 +     *                  <code>month</code>, <code>day</code>, <code>dayOfWeek</code>,
  47.605 +     *                  or <code>millis</code> parameters are out of range
  47.606 +     */
  47.607 +    public int getOffset(int era, int year, int month, int day, int dayOfWeek,
  47.608 +                         int millis)
  47.609 +    {
  47.610 +        if (era != GregorianCalendar.AD && era != GregorianCalendar.BC) {
  47.611 +            throw new IllegalArgumentException("Illegal era " + era);
  47.612 +        }
  47.613 +
  47.614 +        int y = year;
  47.615 +        if (era == GregorianCalendar.BC) {
  47.616 +            // adjust y with the GregorianCalendar-style year numbering.
  47.617 +            y = 1 - y;
  47.618 +        }
  47.619 +
  47.620 +        // If the year isn't representable with the 64-bit long
  47.621 +        // integer in milliseconds, convert the year to an
  47.622 +        // equivalent year. This is required to pass some JCK test cases
  47.623 +        // which are actually useless though because the specified years
  47.624 +        // can't be supported by the Java time system.
  47.625 +        if (y >= 292278994) {
  47.626 +            y = 2800 + y % 2800;
  47.627 +        } else if (y <= -292269054) {
  47.628 +            // y %= 28 also produces an equivalent year, but positive
  47.629 +            // year numbers would be convenient to use the UNIX cal
  47.630 +            // command.
  47.631 +            y = (int) CalendarUtils.mod((long) y, 28);
  47.632 +        }
  47.633 +
  47.634 +        // convert year to its 1-based month value
  47.635 +        int m = month + 1;
  47.636 +
  47.637 +        // First, calculate time as a Gregorian date.
  47.638 +        BaseCalendar cal = gcal;
  47.639 +        BaseCalendar.Date cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  47.640 +        cdate.setDate(y, m, day);
  47.641 +        long time = cal.getTime(cdate); // normalize cdate
  47.642 +        time += millis - rawOffset; // UTC time
  47.643 +
  47.644 +        // If the time value represents a time before the default
  47.645 +        // Gregorian cutover, recalculate time using the Julian
  47.646 +        // calendar system. For the Julian calendar system, the
  47.647 +        // normalized year numbering is ..., -2 (BCE 2), -1 (BCE 1),
  47.648 +        // 1, 2 ... which is different from the GregorianCalendar
  47.649 +        // style year numbering (..., -1, 0 (BCE 1), 1, 2, ...).
  47.650 +        if (time < GregorianCalendar.DEFAULT_GREGORIAN_CUTOVER) {
  47.651 +            cal = (BaseCalendar) CalendarSystem.forName("julian");
  47.652 +            cdate = (BaseCalendar.Date) cal.newCalendarDate(TimeZone.NO_TIMEZONE);
  47.653 +            cdate.setNormalizedDate(y, m, day);
  47.654 +            time = cal.getTime(cdate) + millis - rawOffset;
  47.655 +        }
  47.656 +
  47.657 +        if ((cdate.getNormalizedYear() != y)
  47.658 +            || (cdate.getMonth() != m)
  47.659 +            || (cdate.getDayOfMonth() != day)
  47.660 +            // The validation should be cdate.getDayOfWeek() ==
  47.661 +            // dayOfWeek. However, we don't check dayOfWeek for
  47.662 +            // compatibility.
  47.663 +            || (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY)
  47.664 +            || (millis < 0 || millis >= (24*60*60*1000))) {
  47.665 +            throw new IllegalArgumentException();
  47.666 +        }
  47.667 +
  47.668 +        if (!useDaylight || year < startYear || era != GregorianCalendar.CE) {
  47.669 +            return rawOffset;
  47.670 +        }
  47.671 +
  47.672 +        return getOffset(cal, cdate, y, time);
  47.673 +    }
  47.674 +
  47.675 +    private int getOffset(BaseCalendar cal, BaseCalendar.Date cdate, int year, long time) {
  47.676 +        synchronized (this) {
  47.677 +            if (cacheStart != 0) {
  47.678 +                if (time >= cacheStart && time < cacheEnd) {
  47.679 +                    return rawOffset + dstSavings;
  47.680 +                }
  47.681 +                if (year == cacheYear) {
  47.682 +                    return rawOffset;
  47.683 +                }
  47.684 +            }
  47.685 +        }
  47.686 +
  47.687 +        long start = getStart(cal, cdate, year);
  47.688 +        long end = getEnd(cal, cdate, year);
  47.689 +        int offset = rawOffset;
  47.690 +        if (start <= end) {
  47.691 +            if (time >= start && time < end) {
  47.692 +                offset += dstSavings;
  47.693 +            }
  47.694 +            synchronized (this) {
  47.695 +                cacheYear = year;
  47.696 +                cacheStart = start;
  47.697 +                cacheEnd = end;
  47.698 +            }
  47.699 +        } else {
  47.700 +            if (time < end) {
  47.701 +                // TODO: support Gregorian cutover. The previous year
  47.702 +                // may be in the other calendar system.
  47.703 +                start = getStart(cal, cdate, year - 1);
  47.704 +                if (time >= start) {
  47.705 +                    offset += dstSavings;
  47.706 +                }
  47.707 +            } else if (time >= start) {
  47.708 +                // TODO: support Gregorian cutover. The next year
  47.709 +                // may be in the other calendar system.
  47.710 +                end = getEnd(cal, cdate, year + 1);
  47.711 +                if (time < end) {
  47.712 +                    offset += dstSavings;
  47.713 +                }
  47.714 +            }
  47.715 +            if (start <= end) {
  47.716 +                synchronized (this) {
  47.717 +                    // The start and end transitions are in multiple years.
  47.718 +                    cacheYear = (long) startYear - 1;
  47.719 +                    cacheStart = start;
  47.720 +                    cacheEnd = end;
  47.721 +                }
  47.722 +            }
  47.723 +        }
  47.724 +        return offset;
  47.725 +    }
  47.726 +
  47.727 +    private long getStart(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
  47.728 +        int time = startTime;
  47.729 +        if (startTimeMode != UTC_TIME) {
  47.730 +            time -= rawOffset;
  47.731 +        }
  47.732 +        return getTransition(cal, cdate, startMode, year, startMonth, startDay,
  47.733 +                             startDayOfWeek, time);
  47.734 +    }
  47.735 +
  47.736 +    private long getEnd(BaseCalendar cal, BaseCalendar.Date cdate, int year) {
  47.737 +        int time = endTime;
  47.738 +        if (endTimeMode != UTC_TIME) {
  47.739 +            time -= rawOffset;
  47.740 +        }
  47.741 +        if (endTimeMode == WALL_TIME) {
  47.742 +            time -= dstSavings;
  47.743 +        }
  47.744 +        return getTransition(cal, cdate, endMode, year, endMonth, endDay,
  47.745 +                                        endDayOfWeek, time);
  47.746 +    }
  47.747 +
  47.748 +    private long getTransition(BaseCalendar cal, BaseCalendar.Date cdate,
  47.749 +                               int mode, int year, int month, int dayOfMonth,
  47.750 +                               int dayOfWeek, int timeOfDay) {
  47.751 +        cdate.setNormalizedYear(year);
  47.752 +        cdate.setMonth(month + 1);
  47.753 +        switch (mode) {
  47.754 +        case DOM_MODE:
  47.755 +            cdate.setDayOfMonth(dayOfMonth);
  47.756 +            break;
  47.757 +
  47.758 +        case DOW_IN_MONTH_MODE:
  47.759 +            cdate.setDayOfMonth(1);
  47.760 +            if (dayOfMonth < 0) {
  47.761 +                cdate.setDayOfMonth(cal.getMonthLength(cdate));
  47.762 +            }
  47.763 +            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(dayOfMonth, dayOfWeek, cdate);
  47.764 +            break;
  47.765 +
  47.766 +        case DOW_GE_DOM_MODE:
  47.767 +            cdate.setDayOfMonth(dayOfMonth);
  47.768 +            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(1, dayOfWeek, cdate);
  47.769 +            break;
  47.770 +
  47.771 +        case DOW_LE_DOM_MODE:
  47.772 +            cdate.setDayOfMonth(dayOfMonth);
  47.773 +            cdate = (BaseCalendar.Date) cal.getNthDayOfWeek(-1, dayOfWeek, cdate);
  47.774 +            break;
  47.775 +        }
  47.776 +        return cal.getTime(cdate) + timeOfDay;
  47.777 +    }
  47.778 +
  47.779 +    /**
  47.780 +     * Gets the GMT offset for this time zone.
  47.781 +     * @return the GMT offset value in milliseconds
  47.782 +     * @see #setRawOffset
  47.783 +     */
  47.784 +    public int getRawOffset()
  47.785 +    {
  47.786 +        // The given date will be taken into account while
  47.787 +        // we have the historical time zone data in place.
  47.788 +        return rawOffset;
  47.789 +    }
  47.790 +
  47.791 +    /**
  47.792 +     * Sets the base time zone offset to GMT.
  47.793 +     * This is the offset to add to UTC to get local time.
  47.794 +     * @see #getRawOffset
  47.795 +     */
  47.796 +    public void setRawOffset(int offsetMillis)
  47.797 +    {
  47.798 +        this.rawOffset = offsetMillis;
  47.799 +    }
  47.800 +
  47.801 +    /**
  47.802 +     * Sets the amount of time in milliseconds that the clock is advanced
  47.803 +     * during daylight saving time.
  47.804 +     * @param millisSavedDuringDST the number of milliseconds the time is
  47.805 +     * advanced with respect to standard time when the daylight saving time rules
  47.806 +     * are in effect. A positive number, typically one hour (3600000).
  47.807 +     * @see #getDSTSavings
  47.808 +     * @since 1.2
  47.809 +     */
  47.810 +    public void setDSTSavings(int millisSavedDuringDST) {
  47.811 +        if (millisSavedDuringDST <= 0) {
  47.812 +            throw new IllegalArgumentException("Illegal daylight saving value: "
  47.813 +                                               + millisSavedDuringDST);
  47.814 +        }
  47.815 +        dstSavings = millisSavedDuringDST;
  47.816 +    }
  47.817 +
  47.818 +    /**
  47.819 +     * Returns the amount of time in milliseconds that the clock is
  47.820 +     * advanced during daylight saving time.
  47.821 +     *
  47.822 +     * @return the number of milliseconds the time is advanced with
  47.823 +     * respect to standard time when the daylight saving rules are in
  47.824 +     * effect, or 0 (zero) if this time zone doesn't observe daylight
  47.825 +     * saving time.
  47.826 +     *
  47.827 +     * @see #setDSTSavings
  47.828 +     * @since 1.2
  47.829 +     */
  47.830 +    public int getDSTSavings() {
  47.831 +        return useDaylight ? dstSavings : 0;
  47.832 +    }
  47.833 +
  47.834 +    /**
  47.835 +     * Queries if this time zone uses daylight saving time.
  47.836 +     * @return true if this time zone uses daylight saving time;
  47.837 +     * false otherwise.
  47.838 +     */
  47.839 +    public boolean useDaylightTime()
  47.840 +    {
  47.841 +        return useDaylight;
  47.842 +    }
  47.843 +
  47.844 +    /**
  47.845 +     * Returns {@code true} if this {@code SimpleTimeZone} observes
  47.846 +     * Daylight Saving Time. This method is equivalent to {@link
  47.847 +     * #useDaylightTime()}.
  47.848 +     *
  47.849 +     * @return {@code true} if this {@code SimpleTimeZone} observes
  47.850 +     * Daylight Saving Time; {@code false} otherwise.
  47.851 +     * @since 1.7
  47.852 +     */
  47.853 +    @Override
  47.854 +    public boolean observesDaylightTime() {
  47.855 +        return useDaylightTime();
  47.856 +    }
  47.857 +
  47.858 +    /**
  47.859 +     * Queries if the given date is in daylight saving time.
  47.860 +     * @return true if daylight saving time is in effective at the
  47.861 +     * given date; false otherwise.
  47.862 +     */
  47.863 +    public boolean inDaylightTime(Date date)
  47.864 +    {
  47.865 +        return (getOffset(date.getTime()) != rawOffset);
  47.866 +    }
  47.867 +
  47.868 +    /**
  47.869 +     * Returns a clone of this <code>SimpleTimeZone</code> instance.
  47.870 +     * @return a clone of this instance.
  47.871 +     */
  47.872 +    public Object clone()
  47.873 +    {
  47.874 +        return super.clone();
  47.875 +    }
  47.876 +
  47.877 +    /**
  47.878 +     * Generates the hash code for the SimpleDateFormat object.
  47.879 +     * @return the hash code for this object
  47.880 +     */
  47.881 +    public synchronized int hashCode()
  47.882 +    {
  47.883 +        return startMonth ^ startDay ^ startDayOfWeek ^ startTime ^
  47.884 +            endMonth ^ endDay ^ endDayOfWeek ^ endTime ^ rawOffset;
  47.885 +    }
  47.886 +
  47.887 +    /**
  47.888 +     * Compares the equality of two <code>SimpleTimeZone</code> objects.
  47.889 +     *
  47.890 +     * @param obj  The <code>SimpleTimeZone</code> object to be compared with.
  47.891 +     * @return     True if the given <code>obj</code> is the same as this
  47.892 +     *             <code>SimpleTimeZone</code> object; false otherwise.
  47.893 +     */
  47.894 +    public boolean equals(Object obj)
  47.895 +    {
  47.896 +        if (this == obj) {
  47.897 +            return true;
  47.898 +        }
  47.899 +        if (!(obj instanceof SimpleTimeZone)) {
  47.900 +            return false;
  47.901 +        }
  47.902 +
  47.903 +        SimpleTimeZone that = (SimpleTimeZone) obj;
  47.904 +
  47.905 +        return getID().equals(that.getID()) &&
  47.906 +            hasSameRules(that);
  47.907 +    }
  47.908 +
  47.909 +    /**
  47.910 +     * Returns <code>true</code> if this zone has the same rules and offset as another zone.
  47.911 +     * @param other the TimeZone object to be compared with
  47.912 +     * @return <code>true</code> if the given zone is a SimpleTimeZone and has the
  47.913 +     * same rules and offset as this one
  47.914 +     * @since 1.2
  47.915 +     */
  47.916 +    public boolean hasSameRules(TimeZone other) {
  47.917 +        if (this == other) {
  47.918 +            return true;
  47.919 +        }
  47.920 +        if (!(other instanceof SimpleTimeZone)) {
  47.921 +            return false;
  47.922 +        }
  47.923 +        SimpleTimeZone that = (SimpleTimeZone) other;
  47.924 +        return rawOffset == that.rawOffset &&
  47.925 +            useDaylight == that.useDaylight &&
  47.926 +            (!useDaylight
  47.927 +             // Only check rules if using DST
  47.928 +             || (dstSavings == that.dstSavings &&
  47.929 +                 startMode == that.startMode &&
  47.930 +                 startMonth == that.startMonth &&
  47.931 +                 startDay == that.startDay &&
  47.932 +                 startDayOfWeek == that.startDayOfWeek &&
  47.933 +                 startTime == that.startTime &&
  47.934 +                 startTimeMode == that.startTimeMode &&
  47.935 +                 endMode == that.endMode &&
  47.936 +                 endMonth == that.endMonth &&
  47.937 +                 endDay == that.endDay &&
  47.938 +                 endDayOfWeek == that.endDayOfWeek &&
  47.939 +                 endTime == that.endTime &&
  47.940 +                 endTimeMode == that.endTimeMode &&
  47.941 +                 startYear == that.startYear));
  47.942 +    }
  47.943 +
  47.944 +    /**
  47.945 +     * Returns a string representation of this time zone.
  47.946 +     * @return a string representation of this time zone.
  47.947 +     */
  47.948 +    public String toString() {
  47.949 +        return getClass().getName() +
  47.950 +            "[id=" + getID() +
  47.951 +            ",offset=" + rawOffset +
  47.952 +            ",dstSavings=" + dstSavings +
  47.953 +            ",useDaylight=" + useDaylight +
  47.954 +            ",startYear=" + startYear +
  47.955 +            ",startMode=" + startMode +
  47.956 +            ",startMonth=" + startMonth +
  47.957 +            ",startDay=" + startDay +
  47.958 +            ",startDayOfWeek=" + startDayOfWeek +
  47.959 +            ",startTime=" + startTime +
  47.960 +            ",startTimeMode=" + startTimeMode +
  47.961 +            ",endMode=" + endMode +
  47.962 +            ",endMonth=" + endMonth +
  47.963 +            ",endDay=" + endDay +
  47.964 +            ",endDayOfWeek=" + endDayOfWeek +
  47.965 +            ",endTime=" + endTime +
  47.966 +            ",endTimeMode=" + endTimeMode + ']';
  47.967 +    }
  47.968 +
  47.969 +    // =======================privates===============================
  47.970 +
  47.971 +    /**
  47.972 +     * The month in which daylight saving time starts.  This value must be
  47.973 +     * between <code>Calendar.JANUARY</code> and
  47.974 +     * <code>Calendar.DECEMBER</code> inclusive.  This value must not equal
  47.975 +     * <code>endMonth</code>.
  47.976 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
  47.977 +     * @serial
  47.978 +     */
  47.979 +    private int startMonth;
  47.980 +
  47.981 +    /**
  47.982 +     * This field has two possible interpretations:
  47.983 +     * <dl>
  47.984 +     * <dt><code>startMode == DOW_IN_MONTH</code></dt>
  47.985 +     * <dd>
  47.986 +     * <code>startDay</code> indicates the day of the month of
  47.987 +     * <code>startMonth</code> on which daylight
  47.988 +     * saving time starts, from 1 to 28, 30, or 31, depending on the
  47.989 +     * <code>startMonth</code>.
  47.990 +     * </dd>
  47.991 +     * <dt><code>startMode != DOW_IN_MONTH</code></dt>
  47.992 +     * <dd>
  47.993 +     * <code>startDay</code> indicates which <code>startDayOfWeek</code> in the
  47.994 +     * month <code>startMonth</code> daylight
  47.995 +     * saving time starts on.  For example, a value of +1 and a
  47.996 +     * <code>startDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
  47.997 +     * first Sunday of <code>startMonth</code>.  Likewise, +2 would indicate the
  47.998 +     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
  47.999 +     * </dd>
 47.1000 +     * </dl>
 47.1001 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1002 +     * @serial
 47.1003 +     */
 47.1004 +    private int startDay;
 47.1005 +
 47.1006 +    /**
 47.1007 +     * The day of the week on which daylight saving time starts.  This value
 47.1008 +     * must be between <code>Calendar.SUNDAY</code> and
 47.1009 +     * <code>Calendar.SATURDAY</code> inclusive.
 47.1010 +     * <p>If <code>useDaylight</code> is false or
 47.1011 +     * <code>startMode == DAY_OF_MONTH</code>, this value is ignored.
 47.1012 +     * @serial
 47.1013 +     */
 47.1014 +    private int startDayOfWeek;
 47.1015 +
 47.1016 +    /**
 47.1017 +     * The time in milliseconds after midnight at which daylight saving
 47.1018 +     * time starts.  This value is expressed as wall time, standard time,
 47.1019 +     * or UTC time, depending on the setting of <code>startTimeMode</code>.
 47.1020 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1021 +     * @serial
 47.1022 +     */
 47.1023 +    private int startTime;
 47.1024 +
 47.1025 +    /**
 47.1026 +     * The format of startTime, either WALL_TIME, STANDARD_TIME, or UTC_TIME.
 47.1027 +     * @serial
 47.1028 +     * @since 1.3
 47.1029 +     */
 47.1030 +    private int startTimeMode;
 47.1031 +
 47.1032 +    /**
 47.1033 +     * The month in which daylight saving time ends.  This value must be
 47.1034 +     * between <code>Calendar.JANUARY</code> and
 47.1035 +     * <code>Calendar.UNDECIMBER</code>.  This value must not equal
 47.1036 +     * <code>startMonth</code>.
 47.1037 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1038 +     * @serial
 47.1039 +     */
 47.1040 +    private int endMonth;
 47.1041 +
 47.1042 +    /**
 47.1043 +     * This field has two possible interpretations:
 47.1044 +     * <dl>
 47.1045 +     * <dt><code>endMode == DOW_IN_MONTH</code></dt>
 47.1046 +     * <dd>
 47.1047 +     * <code>endDay</code> indicates the day of the month of
 47.1048 +     * <code>endMonth</code> on which daylight
 47.1049 +     * saving time ends, from 1 to 28, 30, or 31, depending on the
 47.1050 +     * <code>endMonth</code>.
 47.1051 +     * </dd>
 47.1052 +     * <dt><code>endMode != DOW_IN_MONTH</code></dt>
 47.1053 +     * <dd>
 47.1054 +     * <code>endDay</code> indicates which <code>endDayOfWeek</code> in th
 47.1055 +     * month <code>endMonth</code> daylight
 47.1056 +     * saving time ends on.  For example, a value of +1 and a
 47.1057 +     * <code>endDayOfWeek</code> of <code>Calendar.SUNDAY</code> indicates the
 47.1058 +     * first Sunday of <code>endMonth</code>.  Likewise, +2 would indicate the
 47.1059 +     * second Sunday, and -1 the last Sunday.  A value of 0 is illegal.
 47.1060 +     * </dd>
 47.1061 +     * </dl>
 47.1062 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1063 +     * @serial
 47.1064 +     */
 47.1065 +    private int endDay;
 47.1066 +
 47.1067 +    /**
 47.1068 +     * The day of the week on which daylight saving time ends.  This value
 47.1069 +     * must be between <code>Calendar.SUNDAY</code> and
 47.1070 +     * <code>Calendar.SATURDAY</code> inclusive.
 47.1071 +     * <p>If <code>useDaylight</code> is false or
 47.1072 +     * <code>endMode == DAY_OF_MONTH</code>, this value is ignored.
 47.1073 +     * @serial
 47.1074 +     */
 47.1075 +    private int endDayOfWeek;
 47.1076 +
 47.1077 +    /**
 47.1078 +     * The time in milliseconds after midnight at which daylight saving
 47.1079 +     * time ends.  This value is expressed as wall time, standard time,
 47.1080 +     * or UTC time, depending on the setting of <code>endTimeMode</code>.
 47.1081 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1082 +     * @serial
 47.1083 +     */
 47.1084 +    private int endTime;
 47.1085 +
 47.1086 +    /**
 47.1087 +     * The format of endTime, either <code>WALL_TIME</code>,
 47.1088 +     * <code>STANDARD_TIME</code>, or <code>UTC_TIME</code>.
 47.1089 +     * @serial
 47.1090 +     * @since 1.3
 47.1091 +     */
 47.1092 +    private int endTimeMode;
 47.1093 +
 47.1094 +    /**
 47.1095 +     * The year in which daylight saving time is first observed.  This is an {@link GregorianCalendar#AD AD}
 47.1096 +     * value.  If this value is less than 1 then daylight saving time is observed
 47.1097 +     * for all <code>AD</code> years.
 47.1098 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1099 +     * @serial
 47.1100 +     */
 47.1101 +    private int startYear;
 47.1102 +
 47.1103 +    /**
 47.1104 +     * The offset in milliseconds between this zone and GMT.  Negative offsets
 47.1105 +     * are to the west of Greenwich.  To obtain local <em>standard</em> time,
 47.1106 +     * add the offset to GMT time.  To obtain local wall time it may also be
 47.1107 +     * necessary to add <code>dstSavings</code>.
 47.1108 +     * @serial
 47.1109 +     */
 47.1110 +    private int rawOffset;
 47.1111 +
 47.1112 +    /**
 47.1113 +     * A boolean value which is true if and only if this zone uses daylight
 47.1114 +     * saving time.  If this value is false, several other fields are ignored.
 47.1115 +     * @serial
 47.1116 +     */
 47.1117 +    private boolean useDaylight=false; // indicate if this time zone uses DST
 47.1118 +
 47.1119 +    private static final int millisPerHour = 60*60*1000;
 47.1120 +    private static final int millisPerDay  = 24*millisPerHour;
 47.1121 +
 47.1122 +    /**
 47.1123 +     * This field was serialized in JDK 1.1, so we have to keep it that way
 47.1124 +     * to maintain serialization compatibility. However, there's no need to
 47.1125 +     * recreate the array each time we create a new time zone.
 47.1126 +     * @serial An array of bytes containing the values {31, 28, 31, 30, 31, 30,
 47.1127 +     * 31, 31, 30, 31, 30, 31}.  This is ignored as of the Java 2 platform v1.2, however, it must
 47.1128 +     * be streamed out for compatibility with JDK 1.1.
 47.1129 +     */
 47.1130 +    private final byte monthLength[] = staticMonthLength;
 47.1131 +    private final static byte staticMonthLength[] = {31,28,31,30,31,30,31,31,30,31,30,31};
 47.1132 +    private final static byte staticLeapMonthLength[] = {31,29,31,30,31,30,31,31,30,31,30,31};
 47.1133 +
 47.1134 +    /**
 47.1135 +     * Variables specifying the mode of the start rule.  Takes the following
 47.1136 +     * values:
 47.1137 +     * <dl>
 47.1138 +     * <dt><code>DOM_MODE</code></dt>
 47.1139 +     * <dd>
 47.1140 +     * Exact day of week; e.g., March 1.
 47.1141 +     * </dd>
 47.1142 +     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
 47.1143 +     * <dd>
 47.1144 +     * Day of week in month; e.g., last Sunday in March.
 47.1145 +     * </dd>
 47.1146 +     * <dt><code>DOW_GE_DOM_MODE</code></dt>
 47.1147 +     * <dd>
 47.1148 +     * Day of week after day of month; e.g., Sunday on or after March 15.
 47.1149 +     * </dd>
 47.1150 +     * <dt><code>DOW_LE_DOM_MODE</code></dt>
 47.1151 +     * <dd>
 47.1152 +     * Day of week before day of month; e.g., Sunday on or before March 15.
 47.1153 +     * </dd>
 47.1154 +     * </dl>
 47.1155 +     * The setting of this field affects the interpretation of the
 47.1156 +     * <code>startDay</code> field.
 47.1157 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1158 +     * @serial
 47.1159 +     * @since 1.1.4
 47.1160 +     */
 47.1161 +    private int startMode;
 47.1162 +
 47.1163 +    /**
 47.1164 +     * Variables specifying the mode of the end rule.  Takes the following
 47.1165 +     * values:
 47.1166 +     * <dl>
 47.1167 +     * <dt><code>DOM_MODE</code></dt>
 47.1168 +     * <dd>
 47.1169 +     * Exact day of week; e.g., March 1.
 47.1170 +     * </dd>
 47.1171 +     * <dt><code>DOW_IN_MONTH_MODE</code></dt>
 47.1172 +     * <dd>
 47.1173 +     * Day of week in month; e.g., last Sunday in March.
 47.1174 +     * </dd>
 47.1175 +     * <dt><code>DOW_GE_DOM_MODE</code></dt>
 47.1176 +     * <dd>
 47.1177 +     * Day of week after day of month; e.g., Sunday on or after March 15.
 47.1178 +     * </dd>
 47.1179 +     * <dt><code>DOW_LE_DOM_MODE</code></dt>
 47.1180 +     * <dd>
 47.1181 +     * Day of week before day of month; e.g., Sunday on or before March 15.
 47.1182 +     * </dd>
 47.1183 +     * </dl>
 47.1184 +     * The setting of this field affects the interpretation of the
 47.1185 +     * <code>endDay</code> field.
 47.1186 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1187 +     * @serial
 47.1188 +     * @since 1.1.4
 47.1189 +     */
 47.1190 +    private int endMode;
 47.1191 +
 47.1192 +    /**
 47.1193 +     * A positive value indicating the amount of time saved during DST in
 47.1194 +     * milliseconds.
 47.1195 +     * Typically one hour (3600000); sometimes 30 minutes (1800000).
 47.1196 +     * <p>If <code>useDaylight</code> is false, this value is ignored.
 47.1197 +     * @serial
 47.1198 +     * @since 1.1.4
 47.1199 +     */
 47.1200 +    private int dstSavings;
 47.1201 +
 47.1202 +    private static final Gregorian gcal = CalendarSystem.getGregorianCalendar();
 47.1203 +
 47.1204 +    /**
 47.1205 +     * Cache values representing a single period of daylight saving
 47.1206 +     * time. When the cache values are valid, cacheStart is the start
 47.1207 +     * time (inclusive) of daylight saving time and cacheEnd is the
 47.1208 +     * end time (exclusive).
 47.1209 +     *
 47.1210 +     * cacheYear has a year value if both cacheStart and cacheEnd are
 47.1211 +     * in the same year. cacheYear is set to startYear - 1 if
 47.1212 +     * cacheStart and cacheEnd are in different years. cacheStart is 0
 47.1213 +     * if the cache values are void. cacheYear is a long to support
 47.1214 +     * Integer.MIN_VALUE - 1 (JCK requirement).
 47.1215 +     */
 47.1216 +    private transient long cacheYear;
 47.1217 +    private transient long cacheStart;
 47.1218 +    private transient long cacheEnd;
 47.1219 +
 47.1220 +    /**
 47.1221 +     * Constants specifying values of startMode and endMode.
 47.1222 +     */
 47.1223 +    private static final int DOM_MODE          = 1; // Exact day of month, "Mar 1"
 47.1224 +    private static final int DOW_IN_MONTH_MODE = 2; // Day of week in month, "lastSun"
 47.1225 +    private static final int DOW_GE_DOM_MODE   = 3; // Day of week after day of month, "Sun>=15"
 47.1226 +    private static final int DOW_LE_DOM_MODE   = 4; // Day of week before day of month, "Sun<=21"
 47.1227 +
 47.1228 +    /**
 47.1229 +     * Constant for a mode of start or end time specified as wall clock
 47.1230 +     * time.  Wall clock time is standard time for the onset rule, and
 47.1231 +     * daylight time for the end rule.
 47.1232 +     * @since 1.4
 47.1233 +     */
 47.1234 +    public static final int WALL_TIME = 0; // Zero for backward compatibility
 47.1235 +
 47.1236 +    /**
 47.1237 +     * Constant for a mode of start or end time specified as standard time.
 47.1238 +     * @since 1.4
 47.1239 +     */
 47.1240 +    public static final int STANDARD_TIME = 1;
 47.1241 +
 47.1242 +    /**
 47.1243 +     * Constant for a mode of start or end time specified as UTC. European
 47.1244 +     * Union rules are specified as UTC time, for example.
 47.1245 +     * @since 1.4
 47.1246 +     */
 47.1247 +    public static final int UTC_TIME = 2;
 47.1248 +
 47.1249 +    // Proclaim compatibility with 1.1
 47.1250 +    static final long serialVersionUID = -403250971215465050L;
 47.1251 +
 47.1252 +    // the internal serial version which says which version was written
 47.1253 +    // - 0 (default) for version up to JDK 1.1.3
 47.1254 +    // - 1 for version from JDK 1.1.4, which includes 3 new fields
 47.1255 +    // - 2 for JDK 1.3, which includes 2 new fields
 47.1256 +    static final int currentSerialVersion = 2;
 47.1257 +
 47.1258 +    /**
 47.1259 +     * The version of the serialized data on the stream.  Possible values:
 47.1260 +     * <dl>
 47.1261 +     * <dt><b>0</b> or not present on stream</dt>
 47.1262 +     * <dd>
 47.1263 +     * JDK 1.1.3 or earlier.
 47.1264 +     * </dd>
 47.1265 +     * <dt><b>1</b></dt>
 47.1266 +     * <dd>
 47.1267 +     * JDK 1.1.4 or later.  Includes three new fields: <code>startMode</code>,
 47.1268 +     * <code>endMode</code>, and <code>dstSavings</code>.
 47.1269 +     * </dd>
 47.1270 +     * <dt><b>2</b></dt>
 47.1271 +     * <dd>
 47.1272 +     * JDK 1.3 or later.  Includes two new fields: <code>startTimeMode</code>
 47.1273 +     * and <code>endTimeMode</code>.
 47.1274 +     * </dd>
 47.1275 +     * </dl>
 47.1276 +     * When streaming out this class, the most recent format
 47.1277 +     * and the highest allowable <code>serialVersionOnStream</code>
 47.1278 +     * is written.
 47.1279 +     * @serial
 47.1280 +     * @since 1.1.4
 47.1281 +     */
 47.1282 +    private int serialVersionOnStream = currentSerialVersion;
 47.1283 +
 47.1284 +    synchronized private void invalidateCache() {
 47.1285 +        cacheYear = startYear - 1;
 47.1286 +        cacheStart = cacheEnd = 0;
 47.1287 +    }
 47.1288 +
 47.1289 +    //----------------------------------------------------------------------
 47.1290 +    // Rule representation
 47.1291 +    //
 47.1292 +    // We represent the following flavors of rules:
 47.1293 +    //       5        the fifth of the month
 47.1294 +    //       lastSun  the last Sunday in the month
 47.1295 +    //       lastMon  the last Monday in the month
 47.1296 +    //       Sun>=8   first Sunday on or after the eighth
 47.1297 +    //       Sun<=25  last Sunday on or before the 25th
 47.1298 +    // This is further complicated by the fact that we need to remain
 47.1299 +    // backward compatible with the 1.1 FCS.  Finally, we need to minimize
 47.1300 +    // API changes.  In order to satisfy these requirements, we support
 47.1301 +    // three representation systems, and we translate between them.
 47.1302 +    //
 47.1303 +    // INTERNAL REPRESENTATION
 47.1304 +    // This is the format SimpleTimeZone objects take after construction or
 47.1305 +    // streaming in is complete.  Rules are represented directly, using an
 47.1306 +    // unencoded format.  We will discuss the start rule only below; the end
 47.1307 +    // rule is analogous.
 47.1308 +    //   startMode      Takes on enumerated values DAY_OF_MONTH,
 47.1309 +    //                  DOW_IN_MONTH, DOW_AFTER_DOM, or DOW_BEFORE_DOM.
 47.1310 +    //   startDay       The day of the month, or for DOW_IN_MONTH mode, a
 47.1311 +    //                  value indicating which DOW, such as +1 for first,
 47.1312 +    //                  +2 for second, -1 for last, etc.
 47.1313 +    //   startDayOfWeek The day of the week.  Ignored for DAY_OF_MONTH.
 47.1314 +    //
 47.1315 +    // ENCODED REPRESENTATION
 47.1316 +    // This is the format accepted by the constructor and by setStartRule()
 47.1317 +    // and setEndRule().  It uses various combinations of positive, negative,
 47.1318 +    // and zero values to encode the different rules.  This representation
 47.1319 +    // allows us to specify all the different rule flavors without altering
 47.1320 +    // the API.
 47.1321 +    //   MODE              startMonth    startDay    startDayOfWeek
 47.1322 +    //   DOW_IN_MONTH_MODE >=0           !=0         >0
 47.1323 +    //   DOM_MODE          >=0           >0          ==0
 47.1324 +    //   DOW_GE_DOM_MODE   >=0           >0          <0
 47.1325 +    //   DOW_LE_DOM_MODE   >=0           <0          <0
 47.1326 +    //   (no DST)          don't care    ==0         don't care
 47.1327 +    //
 47.1328 +    // STREAMED REPRESENTATION
 47.1329 +    // We must retain binary compatibility with the 1.1 FCS.  The 1.1 code only
 47.1330 +    // handles DOW_IN_MONTH_MODE and non-DST mode, the latter indicated by the
 47.1331 +    // flag useDaylight.  When we stream an object out, we translate into an
 47.1332 +    // approximate DOW_IN_MONTH_MODE representation so the object can be parsed
 47.1333 +    // and used by 1.1 code.  Following that, we write out the full
 47.1334 +    // representation separately so that contemporary code can recognize and
 47.1335 +    // parse it.  The full representation is written in a "packed" format,
 47.1336 +    // consisting of a version number, a length, and an array of bytes.  Future
 47.1337 +    // versions of this class may specify different versions.  If they wish to
 47.1338 +    // include additional data, they should do so by storing them after the
 47.1339 +    // packed representation below.
 47.1340 +    //----------------------------------------------------------------------
 47.1341 +
 47.1342 +    /**
 47.1343 +     * Given a set of encoded rules in startDay and startDayOfMonth, decode
 47.1344 +     * them and set the startMode appropriately.  Do the same for endDay and
 47.1345 +     * endDayOfMonth.  Upon entry, the day of week variables may be zero or
 47.1346 +     * negative, in order to indicate special modes.  The day of month
 47.1347 +     * variables may also be negative.  Upon exit, the mode variables will be
 47.1348 +     * set, and the day of week and day of month variables will be positive.
 47.1349 +     * This method also recognizes a startDay or endDay of zero as indicating
 47.1350 +     * no DST.
 47.1351 +     */
 47.1352 +    private void decodeRules()
 47.1353 +    {
 47.1354 +        decodeStartRule();
 47.1355 +        decodeEndRule();
 47.1356 +    }
 47.1357 +
 47.1358 +    /**
 47.1359 +     * Decode the start rule and validate the parameters.  The parameters are
 47.1360 +     * expected to be in encoded form, which represents the various rule modes
 47.1361 +     * by negating or zeroing certain values.  Representation formats are:
 47.1362 +     * <p>
 47.1363 +     * <pre>
 47.1364 +     *            DOW_IN_MONTH  DOM    DOW>=DOM  DOW<=DOM  no DST
 47.1365 +     *            ------------  -----  --------  --------  ----------
 47.1366 +     * month       0..11        same    same      same     don't care
 47.1367 +     * day        -5..5         1..31   1..31    -1..-31   0
 47.1368 +     * dayOfWeek   1..7         0      -1..-7    -1..-7    don't care
 47.1369 +     * time        0..ONEDAY    same    same      same     don't care
 47.1370 +     * </pre>
 47.1371 +     * The range for month does not include UNDECIMBER since this class is
 47.1372 +     * really specific to GregorianCalendar, which does not use that month.
 47.1373 +     * The range for time includes ONEDAY (vs. ending at ONEDAY-1) because the
 47.1374 +     * end rule is an exclusive limit point.  That is, the range of times that
 47.1375 +     * are in DST include those >= the start and < the end.  For this reason,
 47.1376 +     * it should be possible to specify an end of ONEDAY in order to include the
 47.1377 +     * entire day.  Although this is equivalent to time 0 of the following day,
 47.1378 +     * it's not always possible to specify that, for example, on December 31.
 47.1379 +     * While arguably the start range should still be 0..ONEDAY-1, we keep
 47.1380 +     * the start and end ranges the same for consistency.
 47.1381 +     */
 47.1382 +    private void decodeStartRule() {
 47.1383 +        useDaylight = (startDay != 0) && (endDay != 0);
 47.1384 +        if (startDay != 0) {
 47.1385 +            if (startMonth < Calendar.JANUARY || startMonth > Calendar.DECEMBER) {
 47.1386 +                throw new IllegalArgumentException(
 47.1387 +                        "Illegal start month " + startMonth);
 47.1388 +            }
 47.1389 +            if (startTime < 0 || startTime > millisPerDay) {
 47.1390 +                throw new IllegalArgumentException(
 47.1391 +                        "Illegal start time " + startTime);
 47.1392 +            }
 47.1393 +            if (startDayOfWeek == 0) {
 47.1394 +                startMode = DOM_MODE;
 47.1395 +            } else {
 47.1396 +                if (startDayOfWeek > 0) {
 47.1397 +                    startMode = DOW_IN_MONTH_MODE;
 47.1398 +                } else {
 47.1399 +                    startDayOfWeek = -startDayOfWeek;
 47.1400 +                    if (startDay > 0) {
 47.1401 +                        startMode = DOW_GE_DOM_MODE;
 47.1402 +                    } else {
 47.1403 +                        startDay = -startDay;
 47.1404 +                        startMode = DOW_LE_DOM_MODE;
 47.1405 +                    }
 47.1406 +                }
 47.1407 +                if (startDayOfWeek > Calendar.SATURDAY) {
 47.1408 +                    throw new IllegalArgumentException(
 47.1409 +                           "Illegal start day of week " + startDayOfWeek);
 47.1410 +                }
 47.1411 +            }
 47.1412 +            if (startMode == DOW_IN_MONTH_MODE) {
 47.1413 +                if (startDay < -5 || startDay > 5) {
 47.1414 +                    throw new IllegalArgumentException(
 47.1415 +                            "Illegal start day of week in month " + startDay);
 47.1416 +                }
 47.1417 +            } else if (startDay < 1 || startDay > staticMonthLength[startMonth]) {
 47.1418 +                throw new IllegalArgumentException(
 47.1419 +                        "Illegal start day " + startDay);
 47.1420 +            }
 47.1421 +        }
 47.1422 +    }
 47.1423 +
 47.1424 +    /**
 47.1425 +     * Decode the end rule and validate the parameters.  This method is exactly
 47.1426 +     * analogous to decodeStartRule().
 47.1427 +     * @see decodeStartRule
 47.1428 +     */
 47.1429 +    private void decodeEndRule() {
 47.1430 +        useDaylight = (startDay != 0) && (endDay != 0);
 47.1431 +        if (endDay != 0) {
 47.1432 +            if (endMonth < Calendar.JANUARY || endMonth > Calendar.DECEMBER) {
 47.1433 +                throw new IllegalArgumentException(
 47.1434 +                        "Illegal end month " + endMonth);
 47.1435 +            }
 47.1436 +            if (endTime < 0 || endTime > millisPerDay) {
 47.1437 +                throw new IllegalArgumentException(
 47.1438 +                        "Illegal end time " + endTime);
 47.1439 +            }
 47.1440 +            if (endDayOfWeek == 0) {
 47.1441 +                endMode = DOM_MODE;
 47.1442 +            } else {
 47.1443 +                if (endDayOfWeek > 0) {
 47.1444 +                    endMode = DOW_IN_MONTH_MODE;
 47.1445 +                } else {
 47.1446 +                    endDayOfWeek = -endDayOfWeek;
 47.1447 +                    if (endDay > 0) {
 47.1448 +                        endMode = DOW_GE_DOM_MODE;
 47.1449 +                    } else {
 47.1450 +                        endDay = -endDay;
 47.1451 +                        endMode = DOW_LE_DOM_MODE;
 47.1452 +                    }
 47.1453 +                }
 47.1454 +                if (endDayOfWeek > Calendar.SATURDAY) {
 47.1455 +                    throw new IllegalArgumentException(
 47.1456 +                           "Illegal end day of week " + endDayOfWeek);
 47.1457 +                }
 47.1458 +            }
 47.1459 +            if (endMode == DOW_IN_MONTH_MODE) {
 47.1460 +                if (endDay < -5 || endDay > 5) {
 47.1461 +                    throw new IllegalArgumentException(
 47.1462 +                            "Illegal end day of week in month " + endDay);
 47.1463 +                }
 47.1464 +            } else if (endDay < 1 || endDay > staticMonthLength[endMonth]) {
 47.1465 +                throw new IllegalArgumentException(
 47.1466 +                        "Illegal end day " + endDay);
 47.1467 +            }
 47.1468 +        }
 47.1469 +    }
 47.1470 +
 47.1471 +    /**
 47.1472 +     * Make rules compatible to 1.1 FCS code.  Since 1.1 FCS code only understands
 47.1473 +     * day-of-week-in-month rules, we must modify other modes of rules to their
 47.1474 +     * approximate equivalent in 1.1 FCS terms.  This method is used when streaming
 47.1475 +     * out objects of this class.  After it is called, the rules will be modified,
 47.1476 +     * with a possible loss of information.  startMode and endMode will NOT be
 47.1477 +     * altered, even though semantically they should be set to DOW_IN_MONTH_MODE,
 47.1478 +     * since the rule modification is only intended to be temporary.
 47.1479 +     */
 47.1480 +    private void makeRulesCompatible()
 47.1481 +    {
 47.1482 +        switch (startMode) {
 47.1483 +        case DOM_MODE:
 47.1484 +            startDay = 1 + (startDay / 7);
 47.1485 +            startDayOfWeek = Calendar.SUNDAY;
 47.1486 +            break;
 47.1487 +
 47.1488 +        case DOW_GE_DOM_MODE:
 47.1489 +            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
 47.1490 +            // that is, Sun>=1 == firstSun.
 47.1491 +            if (startDay != 1) {
 47.1492 +                startDay = 1 + (startDay / 7);
 47.1493 +            }
 47.1494 +            break;
 47.1495 +
 47.1496 +        case DOW_LE_DOM_MODE:
 47.1497 +            if (startDay >= 30) {
 47.1498 +                startDay = -1;
 47.1499 +            } else {
 47.1500 +                startDay = 1 + (startDay / 7);
 47.1501 +            }
 47.1502 +            break;
 47.1503 +        }
 47.1504 +
 47.1505 +        switch (endMode) {
 47.1506 +        case DOM_MODE:
 47.1507 +            endDay = 1 + (endDay / 7);
 47.1508 +            endDayOfWeek = Calendar.SUNDAY;
 47.1509 +            break;
 47.1510 +
 47.1511 +        case DOW_GE_DOM_MODE:
 47.1512 +            // A day-of-month of 1 is equivalent to DOW_IN_MONTH_MODE
 47.1513 +            // that is, Sun>=1 == firstSun.
 47.1514 +            if (endDay != 1) {
 47.1515 +                endDay = 1 + (endDay / 7);
 47.1516 +            }
 47.1517 +            break;
 47.1518 +
 47.1519 +        case DOW_LE_DOM_MODE:
 47.1520 +            if (endDay >= 30) {
 47.1521 +                endDay = -1;
 47.1522 +            } else {
 47.1523 +                endDay = 1 + (endDay / 7);
 47.1524 +            }
 47.1525 +            break;
 47.1526 +        }
 47.1527 +
 47.1528 +        /*
 47.1529 +         * Adjust the start and end times to wall time.  This works perfectly
 47.1530 +         * well unless it pushes into the next or previous day.  If that
 47.1531 +         * happens, we attempt to adjust the day rule somewhat crudely.  The day
 47.1532 +         * rules have been forced into DOW_IN_MONTH mode already, so we change
 47.1533 +         * the day of week to move forward or back by a day.  It's possible to
 47.1534 +         * make a more refined adjustment of the original rules first, but in
 47.1535 +         * most cases this extra effort will go to waste once we adjust the day
 47.1536 +         * rules anyway.
 47.1537 +         */
 47.1538 +        switch (startTimeMode) {
 47.1539 +        case UTC_TIME:
 47.1540 +            startTime += rawOffset;
 47.1541 +            break;
 47.1542 +        }
 47.1543 +        while (startTime < 0) {
 47.1544 +            startTime += millisPerDay;
 47.1545 +            startDayOfWeek = 1 + ((startDayOfWeek+5) % 7); // Back 1 day
 47.1546 +        }
 47.1547 +        while (startTime >= millisPerDay) {
 47.1548 +            startTime -= millisPerDay;
 47.1549 +            startDayOfWeek = 1 + (startDayOfWeek % 7); // Forward 1 day
 47.1550 +        }
 47.1551 +
 47.1552 +        switch (endTimeMode) {
 47.1553 +        case UTC_TIME:
 47.1554 +            endTime += rawOffset + dstSavings;
 47.1555 +            break;
 47.1556 +        case STANDARD_TIME:
 47.1557 +            endTime += dstSavings;
 47.1558 +        }
 47.1559 +        while (endTime < 0) {
 47.1560 +            endTime += millisPerDay;
 47.1561 +            endDayOfWeek = 1 + ((endDayOfWeek+5) % 7); // Back 1 day
 47.1562 +        }
 47.1563 +        while (endTime >= millisPerDay) {
 47.1564 +            endTime -= millisPerDay;
 47.1565 +            endDayOfWeek = 1 + (endDayOfWeek % 7); // Forward 1 day
 47.1566 +        }
 47.1567 +    }
 47.1568 +
 47.1569 +    /**
 47.1570 +     * Pack the start and end rules into an array of bytes.  Only pack
 47.1571 +     * data which is not preserved by makeRulesCompatible.
 47.1572 +     */
 47.1573 +    private byte[] packRules()
 47.1574 +    {
 47.1575 +        byte[] rules = new byte[6];
 47.1576 +        rules[0] = (byte)startDay;
 47.1577 +        rules[1] = (byte)startDayOfWeek;
 47.1578 +        rules[2] = (byte)endDay;
 47.1579 +        rules[3] = (byte)endDayOfWeek;
 47.1580 +
 47.1581 +        // As of serial version 2, include time modes
 47.1582 +        rules[4] = (byte)startTimeMode;
 47.1583 +        rules[5] = (byte)endTimeMode;
 47.1584 +
 47.1585 +        return rules;
 47.1586 +    }
 47.1587 +
 47.1588 +    /**
 47.1589 +     * Given an array of bytes produced by packRules, interpret them
 47.1590 +     * as the start and end rules.
 47.1591 +     */
 47.1592 +    private void unpackRules(byte[] rules)
 47.1593 +    {
 47.1594 +        startDay       = rules[0];
 47.1595 +        startDayOfWeek = rules[1];
 47.1596 +        endDay         = rules[2];
 47.1597 +        endDayOfWeek   = rules[3];
 47.1598 +
 47.1599 +        // As of serial version 2, include time modes
 47.1600 +        if (rules.length >= 6) {
 47.1601 +            startTimeMode = rules[4];
 47.1602 +            endTimeMode   = rules[5];
 47.1603 +        }
 47.1604 +    }
 47.1605 +
 47.1606 +    /**
 47.1607 +     * Pack the start and end times into an array of bytes.  This is required
 47.1608 +     * as of serial version 2.
 47.1609 +     */
 47.1610 +    private int[] packTimes() {
 47.1611 +        int[] times = new int[2];
 47.1612 +        times[0] = startTime;
 47.1613 +        times[1] = endTime;
 47.1614 +        return times;
 47.1615 +    }
 47.1616 +
 47.1617 +    /**
 47.1618 +     * Unpack the start and end times from an array of bytes.  This is required
 47.1619 +     * as of serial version 2.
 47.1620 +     */
 47.1621 +    private void unpackTimes(int[] times) {
 47.1622 +        startTime = times[0];
 47.1623 +        endTime = times[1];
 47.1624 +    }
 47.1625 +
 47.1626 +    /**
 47.1627 +     * Save the state of this object to a stream (i.e., serialize it).
 47.1628 +     *
 47.1629 +     * @serialData We write out two formats, a JDK 1.1 compatible format, using
 47.1630 +     * <code>DOW_IN_MONTH_MODE</code> rules, in the required section, followed
 47.1631 +     * by the full rules, in packed format, in the optional section.  The
 47.1632 +     * optional section will be ignored by JDK 1.1 code upon stream in.
 47.1633 +     * <p> Contents of the optional section: The length of a byte array is
 47.1634 +     * emitted (int); this is 4 as of this release. The byte array of the given
 47.1635 +     * length is emitted. The contents of the byte array are the true values of
 47.1636 +     * the fields <code>startDay</code>, <code>startDayOfWeek</code>,
 47.1637 +     * <code>endDay</code>, and <code>endDayOfWeek</code>.  The values of these
 47.1638 +     * fields in the required section are approximate values suited to the rule
 47.1639 +     * mode <code>DOW_IN_MONTH_MODE</code>, which is the only mode recognized by
 47.1640 +     * JDK 1.1.
 47.1641 +     */
 47.1642 +    private void writeObject(ObjectOutputStream stream)
 47.1643 +         throws IOException
 47.1644 +    {
 47.1645 +        // Construct a binary rule
 47.1646 +        byte[] rules = packRules();
 47.1647 +        int[] times = packTimes();
 47.1648 +
 47.1649 +        // Convert to 1.1 FCS rules.  This step may cause us to lose information.
 47.1650 +        makeRulesCompatible();
 47.1651 +
 47.1652 +        // Write out the 1.1 FCS rules
 47.1653 +        stream.defaultWriteObject();
 47.1654 +
 47.1655 +        // Write out the binary rules in the optional data area of the stream.
 47.1656 +        stream.writeInt(rules.length);
 47.1657 +        stream.write(rules);
 47.1658 +        stream.writeObject(times);
 47.1659 +
 47.1660 +        // Recover the original rules.  This recovers the information lost
 47.1661 +        // by makeRulesCompatible.
 47.1662 +        unpackRules(rules);
 47.1663 +        unpackTimes(times);
 47.1664 +    }
 47.1665 +
 47.1666 +    /**
 47.1667 +     * Reconstitute this object from a stream (i.e., deserialize it).
 47.1668 +     *
 47.1669 +     * We handle both JDK 1.1
 47.1670 +     * binary formats and full formats with a packed byte array.
 47.1671 +     */
 47.1672 +    private void readObject(ObjectInputStream stream)
 47.1673 +         throws IOException, ClassNotFoundException
 47.1674 +    {
 47.1675 +        stream.defaultReadObject();
 47.1676 +
 47.1677 +        if (serialVersionOnStream < 1) {
 47.1678 +            // Fix a bug in the 1.1 SimpleTimeZone code -- namely,
 47.1679 +            // startDayOfWeek and endDayOfWeek were usually uninitialized.  We can't do
 47.1680 +            // too much, so we assume SUNDAY, which actually works most of the time.
 47.1681 +            if (startDayOfWeek == 0) {
 47.1682 +                startDayOfWeek = Calendar.SUNDAY;
 47.1683 +            }
 47.1684 +            if (endDayOfWeek == 0) {
 47.1685 +                endDayOfWeek = Calendar.SUNDAY;
 47.1686 +            }
 47.1687 +
 47.1688 +            // The variables dstSavings, startMode, and endMode are post-1.1, so they
 47.1689 +            // won't be present if we're reading from a 1.1 stream.  Fix them up.
 47.1690 +            startMode = endMode = DOW_IN_MONTH_MODE;
 47.1691 +            dstSavings = millisPerHour;
 47.1692 +        } else {
 47.1693 +            // For 1.1.4, in addition to the 3 new instance variables, we also
 47.1694 +            // store the actual rules (which have not be made compatible with 1.1)
 47.1695 +            // in the optional area.  Read them in here and parse them.
 47.1696 +            int length = stream.readInt();
 47.1697 +            byte[] rules = new byte[length];
 47.1698 +            stream.readFully(rules);
 47.1699 +            unpackRules(rules);
 47.1700 +        }
 47.1701 +
 47.1702 +        if (serialVersionOnStream >= 2) {
 47.1703 +            int[] times = (int[]) stream.readObject();
 47.1704 +            unpackTimes(times);
 47.1705 +        }
 47.1706 +
 47.1707 +        serialVersionOnStream = currentSerialVersion;
 47.1708 +    }
 47.1709 +}
    48.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    48.2 +++ b/rt/emul/compact/src/main/java/java/util/TimeZone.java	Thu Oct 03 15:40:35 2013 +0200
    48.3 @@ -0,0 +1,864 @@
    48.4 +/*
    48.5 + * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
    48.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    48.7 + *
    48.8 + * This code is free software; you can redistribute it and/or modify it
    48.9 + * under the terms of the GNU General Public License version 2 only, as
   48.10 + * published by the Free Software Foundation.  Oracle designates this
   48.11 + * particular file as subject to the "Classpath" exception as provided
   48.12 + * by Oracle in the LICENSE file that accompanied this code.
   48.13 + *
   48.14 + * This code is distributed in the hope that it will be useful, but WITHOUT
   48.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   48.16 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   48.17 + * version 2 for more details (a copy is included in the LICENSE file that
   48.18 + * accompanied this code).
   48.19 + *
   48.20 + * You should have received a copy of the GNU General Public License version
   48.21 + * 2 along with this work; if not, write to the Free Software Foundation,
   48.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   48.23 + *
   48.24 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   48.25 + * or visit www.oracle.com if you need additional information or have any
   48.26 + * questions.
   48.27 + */
   48.28 +
   48.29 +/*
   48.30 + * (C) Copyright Taligent, Inc. 1996 - All Rights Reserved
   48.31 + * (C) Copyright IBM Corp. 1996 - All Rights Reserved
   48.32 + *
   48.33 + *   The original version of this source code and documentation is copyrighted
   48.34 + * and owned by Taligent, Inc., a wholly-owned subsidiary of IBM. These
   48.35 + * materials are provided under terms of a License Agreement between Taligent
   48.36 + * and Sun. This technology is protected by multiple US and International
   48.37 + * patents. This notice and attribution to Taligent may not be removed.
   48.38 + *   Taligent is a registered trademark of Taligent, Inc.
   48.39 + *
   48.40 + */
   48.41 +
   48.42 +package java.util;
   48.43 +
   48.44 +import java.io.Serializable;
   48.45 +import java.lang.ref.SoftReference;
   48.46 +import java.security.AccessController;
   48.47 +import java.security.PrivilegedAction;
   48.48 +import java.util.concurrent.ConcurrentHashMap;
   48.49 +import sun.security.action.GetPropertyAction;
   48.50 +import sun.util.TimeZoneNameUtility;
   48.51 +import sun.util.calendar.ZoneInfo;
   48.52 +import sun.util.calendar.ZoneInfoFile;
   48.53 +
   48.54 +/**
   48.55 + * <code>TimeZone</code> represents a time zone offset, and also figures out daylight
   48.56 + * savings.
   48.57 + *
   48.58 + * <p>
   48.59 + * Typically, you get a <code>TimeZone</code> using <code>getDefault</code>
   48.60 + * which creates a <code>TimeZone</code> based on the time zone where the program
   48.61 + * is running. For example, for a program running in Japan, <code>getDefault</code>
   48.62 + * creates a <code>TimeZone</code> object based on Japanese Standard Time.
   48.63 + *
   48.64 + * <p>
   48.65 + * You can also get a <code>TimeZone</code> using <code>getTimeZone</code>
   48.66 + * along with a time zone ID. For instance, the time zone ID for the
   48.67 + * U.S. Pacific Time zone is "America/Los_Angeles". So, you can get a
   48.68 + * U.S. Pacific Time <code>TimeZone</code> object with:
   48.69 + * <blockquote><pre>
   48.70 + * TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
   48.71 + * </pre></blockquote>
   48.72 + * You can use the <code>getAvailableIDs</code> method to iterate through
   48.73 + * all the supported time zone IDs. You can then choose a
   48.74 + * supported ID to get a <code>TimeZone</code>.
   48.75 + * If the time zone you want is not represented by one of the
   48.76 + * supported IDs, then a custom time zone ID can be specified to
   48.77 + * produce a TimeZone. The syntax of a custom time zone ID is:
   48.78 + *
   48.79 + * <blockquote><pre>
   48.80 + * <a name="CustomID"><i>CustomID:</i></a>
   48.81 + *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <code>:</code> <i>Minutes</i>
   48.82 + *         <code>GMT</code> <i>Sign</i> <i>Hours</i> <i>Minutes</i>
   48.83 + *         <code>GMT</code> <i>Sign</i> <i>Hours</i>
   48.84 + * <i>Sign:</i> one of
   48.85 + *         <code>+ -</code>
   48.86 + * <i>Hours:</i>
   48.87 + *         <i>Digit</i>
   48.88 + *         <i>Digit</i> <i>Digit</i>
   48.89 + * <i>Minutes:</i>
   48.90 + *         <i>Digit</i> <i>Digit</i>
   48.91 + * <i>Digit:</i> one of
   48.92 + *         <code>0 1 2 3 4 5 6 7 8 9</code>
   48.93 + * </pre></blockquote>
   48.94 + *
   48.95 + * <i>Hours</i> must be between 0 to 23 and <i>Minutes</i> must be
   48.96 + * between 00 to 59.  For example, "GMT+10" and "GMT+0010" mean ten
   48.97 + * hours and ten minutes ahead of GMT, respectively.
   48.98 + * <p>
   48.99 + * The format is locale independent and digits must be taken from the
  48.100 + * Basic Latin block of the Unicode standard. No daylight saving time
  48.101 + * transition schedule can be specified with a custom time zone ID. If
  48.102 + * the specified string doesn't match the syntax, <code>"GMT"</code>
  48.103 + * is used.
  48.104 + * <p>
  48.105 + * When creating a <code>TimeZone</code>, the specified custom time
  48.106 + * zone ID is normalized in the following syntax:
  48.107 + * <blockquote><pre>
  48.108 + * <a name="NormalizedCustomID"><i>NormalizedCustomID:</i></a>
  48.109 + *         <code>GMT</code> <i>Sign</i> <i>TwoDigitHours</i> <code>:</code> <i>Minutes</i>
  48.110 + * <i>Sign:</i> one of
  48.111 + *         <code>+ -</code>
  48.112 + * <i>TwoDigitHours:</i>
  48.113 + *         <i>Digit</i> <i>Digit</i>
  48.114 + * <i>Minutes:</i>
  48.115 + *         <i>Digit</i> <i>Digit</i>
  48.116 + * <i>Digit:</i> one of
  48.117 + *         <code>0 1 2 3 4 5 6 7 8 9</code>
  48.118 + * </pre></blockquote>
  48.119 + * For example, TimeZone.getTimeZone("GMT-8").getID() returns "GMT-08:00".
  48.120 + *
  48.121 + * <h4>Three-letter time zone IDs</h4>
  48.122 + *
  48.123 + * For compatibility with JDK 1.1.x, some other three-letter time zone IDs
  48.124 + * (such as "PST", "CTT", "AST") are also supported. However, <strong>their
  48.125 + * use is deprecated</strong> because the same abbreviation is often used
  48.126 + * for multiple time zones (for example, "CST" could be U.S. "Central Standard
  48.127 + * Time" and "China Standard Time"), and the Java platform can then only
  48.128 + * recognize one of them.
  48.129 + *
  48.130 + *
  48.131 + * @see          Calendar
  48.132 + * @see          GregorianCalendar
  48.133 + * @see          SimpleTimeZone
  48.134 + * @author       Mark Davis, David Goldsmith, Chen-Lieh Huang, Alan Liu
  48.135 + * @since        JDK1.1
  48.136 + */
  48.137 +abstract public class TimeZone implements Serializable, Cloneable {
  48.138 +    /**
  48.139 +     * Sole constructor.  (For invocation by subclass constructors, typically
  48.140 +     * implicit.)
  48.141 +     */
  48.142 +    public TimeZone() {
  48.143 +    }
  48.144 +
  48.145 +    /**
  48.146 +     * A style specifier for <code>getDisplayName()</code> indicating
  48.147 +     * a short name, such as "PST."
  48.148 +     * @see #LONG
  48.149 +     * @since 1.2
  48.150 +     */
  48.151 +    public static final int SHORT = 0;
  48.152 +
  48.153 +    /**
  48.154 +     * A style specifier for <code>getDisplayName()</code> indicating
  48.155 +     * a long name, such as "Pacific Standard Time."
  48.156 +     * @see #SHORT
  48.157 +     * @since 1.2
  48.158 +     */
  48.159 +    public static final int LONG  = 1;
  48.160 +
  48.161 +    // Constants used internally; unit is milliseconds
  48.162 +    private static final int ONE_MINUTE = 60*1000;
  48.163 +    private static final int ONE_HOUR   = 60*ONE_MINUTE;
  48.164 +    private static final int ONE_DAY    = 24*ONE_HOUR;
  48.165 +
  48.166 +    // Proclaim serialization compatibility with JDK 1.1
  48.167 +    static final long serialVersionUID = 3581463369166924961L;
  48.168 +
  48.169 +    /**
  48.170 +     * Gets the time zone offset, for current date, modified in case of
  48.171 +     * daylight savings. This is the offset to add to UTC to get local time.
  48.172 +     * <p>
  48.173 +     * This method returns a historically correct offset if an
  48.174 +     * underlying <code>TimeZone</code> implementation subclass
  48.175 +     * supports historical Daylight Saving Time schedule and GMT
  48.176 +     * offset changes.
  48.177 +     *
  48.178 +     * @param era the era of the given date.
  48.179 +     * @param year the year in the given date.
  48.180 +     * @param month the month in the given date.
  48.181 +     * Month is 0-based. e.g., 0 for January.
  48.182 +     * @param day the day-in-month of the given date.
  48.183 +     * @param dayOfWeek the day-of-week of the given date.
  48.184 +     * @param milliseconds the milliseconds in day in <em>standard</em>
  48.185 +     * local time.
  48.186 +     *
  48.187 +     * @return the offset in milliseconds to add to GMT to get local time.
  48.188 +     *
  48.189 +     * @see Calendar#ZONE_OFFSET
  48.190 +     * @see Calendar#DST_OFFSET
  48.191 +     */
  48.192 +    public abstract int getOffset(int era, int year, int month, int day,
  48.193 +                                  int dayOfWeek, int milliseconds);
  48.194 +
  48.195 +    /**
  48.196 +     * Returns the offset of this time zone from UTC at the specified
  48.197 +     * date. If Daylight Saving Time is in effect at the specified
  48.198 +     * date, the offset value is adjusted with the amount of daylight
  48.199 +     * saving.
  48.200 +     * <p>
  48.201 +     * This method returns a historically correct offset value if an
  48.202 +     * underlying TimeZone implementation subclass supports historical
  48.203 +     * Daylight Saving Time schedule and GMT offset changes.
  48.204 +     *
  48.205 +     * @param date the date represented in milliseconds since January 1, 1970 00:00:00 GMT
  48.206 +     * @return the amount of time in milliseconds to add to UTC to get local time.
  48.207 +     *
  48.208 +     * @see Calendar#ZONE_OFFSET
  48.209 +     * @see Calendar#DST_OFFSET
  48.210 +     * @since 1.4
  48.211 +     */
  48.212 +    public int getOffset(long date) {
  48.213 +        if (inDaylightTime(new Date(date))) {
  48.214 +            return getRawOffset() + getDSTSavings();
  48.215 +        }
  48.216 +        return getRawOffset();
  48.217 +    }
  48.218 +
  48.219 +    /**
  48.220 +     * Gets the raw GMT offset and the amount of daylight saving of this
  48.221 +     * time zone at the given time.
  48.222 +     * @param date the milliseconds (since January 1, 1970,
  48.223 +     * 00:00:00.000 GMT) at which the time zone offset and daylight
  48.224 +     * saving amount are found
  48.225 +     * @param offset an array of int where the raw GMT offset
  48.226 +     * (offset[0]) and daylight saving amount (offset[1]) are stored,
  48.227 +     * or null if those values are not needed. The method assumes that
  48.228 +     * the length of the given array is two or larger.
  48.229 +     * @return the total amount of the raw GMT offset and daylight
  48.230 +     * saving at the specified date.
  48.231 +     *
  48.232 +     * @see Calendar#ZONE_OFFSET
  48.233 +     * @see Calendar#DST_OFFSET
  48.234 +     */
  48.235 +    int getOffsets(long date, int[] offsets) {
  48.236 +        int rawoffset = getRawOffset();
  48.237 +        int dstoffset = 0;
  48.238 +        if (inDaylightTime(new Date(date))) {
  48.239 +            dstoffset = getDSTSavings();
  48.240 +        }
  48.241 +        if (offsets != null) {
  48.242 +            offsets[0] = rawoffset;
  48.243 +            offsets[1] = dstoffset;
  48.244 +        }
  48.245 +        return rawoffset + dstoffset;
  48.246 +    }
  48.247 +
  48.248 +    /**
  48.249 +     * Sets the base time zone offset to GMT.
  48.250 +     * This is the offset to add to UTC to get local time.
  48.251 +     * <p>
  48.252 +     * If an underlying <code>TimeZone</code> implementation subclass
  48.253 +     * supports historical GMT offset changes, the specified GMT
  48.254 +     * offset is set as the latest GMT offset and the difference from
  48.255 +     * the known latest GMT offset value is used to adjust all
  48.256 +     * historical GMT offset values.
  48.257 +     *
  48.258 +     * @param offsetMillis the given base time zone offset to GMT.
  48.259 +     */
  48.260 +    abstract public void setRawOffset(int offsetMillis);
  48.261 +
  48.262 +    /**
  48.263 +     * Returns the amount of time in milliseconds to add to UTC to get
  48.264 +     * standard time in this time zone. Because this value is not
  48.265 +     * affected by daylight saving time, it is called <I>raw
  48.266 +     * offset</I>.
  48.267 +     * <p>
  48.268 +     * If an underlying <code>TimeZone</code> implementation subclass
  48.269 +     * supports historical GMT offset changes, the method returns the
  48.270 +     * raw offset value of the current date. In Honolulu, for example,
  48.271 +     * its raw offset changed from GMT-10:30 to GMT-10:00 in 1947, and
  48.272 +     * this method always returns -36000000 milliseconds (i.e., -10
  48.273 +     * hours).
  48.274 +     *
  48.275 +     * @return the amount of raw offset time in milliseconds to add to UTC.
  48.276 +     * @see Calendar#ZONE_OFFSET
  48.277 +     */
  48.278 +    public abstract int getRawOffset();
  48.279 +
  48.280 +    /**
  48.281 +     * Gets the ID of this time zone.
  48.282 +     * @return the ID of this time zone.
  48.283 +     */
  48.284 +    public String getID()
  48.285 +    {
  48.286 +        return ID;
  48.287 +    }
  48.288 +
  48.289 +    /**
  48.290 +     * Sets the time zone ID. This does not change any other data in
  48.291 +     * the time zone object.
  48.292 +     * @param ID the new time zone ID.
  48.293 +     */
  48.294 +    public void setID(String ID)
  48.295 +    {
  48.296 +        if (ID == null) {
  48.297 +            throw new NullPointerException();
  48.298 +        }
  48.299 +        this.ID = ID;
  48.300 +    }
  48.301 +
  48.302 +    /**
  48.303 +     * Returns a long standard time name of this {@code TimeZone} suitable for
  48.304 +     * presentation to the user in the default locale.
  48.305 +     *
  48.306 +     * <p>This method is equivalent to:
  48.307 +     * <pre><blockquote>
  48.308 +     * getDisplayName(false, {@link #LONG},
  48.309 +     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
  48.310 +     * </blockquote></pre>
  48.311 +     *
  48.312 +     * @return the human-readable name of this time zone in the default locale.
  48.313 +     * @since 1.2
  48.314 +     * @see #getDisplayName(boolean, int, Locale)
  48.315 +     * @see Locale#getDefault(Locale.Category)
  48.316 +     * @see Locale.Category
  48.317 +     */
  48.318 +    public final String getDisplayName() {
  48.319 +        return getDisplayName(false, LONG,
  48.320 +                              Locale.getDefault(Locale.Category.DISPLAY));
  48.321 +    }
  48.322 +
  48.323 +    /**
  48.324 +     * Returns a long standard time name of this {@code TimeZone} suitable for
  48.325 +     * presentation to the user in the specified {@code locale}.
  48.326 +     *
  48.327 +     * <p>This method is equivalent to:
  48.328 +     * <pre><blockquote>
  48.329 +     * getDisplayName(false, {@link #LONG}, locale)
  48.330 +     * </blockquote></pre>
  48.331 +     *
  48.332 +     * @param locale the locale in which to supply the display name.
  48.333 +     * @return the human-readable name of this time zone in the given locale.
  48.334 +     * @exception NullPointerException if {@code locale} is {@code null}.
  48.335 +     * @since 1.2
  48.336 +     * @see #getDisplayName(boolean, int, Locale)
  48.337 +     */
  48.338 +    public final String getDisplayName(Locale locale) {
  48.339 +        return getDisplayName(false, LONG, locale);
  48.340 +    }
  48.341 +
  48.342 +    /**
  48.343 +     * Returns a name in the specified {@code style} of this {@code TimeZone}
  48.344 +     * suitable for presentation to the user in the default locale. If the
  48.345 +     * specified {@code daylight} is {@code true}, a Daylight Saving Time name
  48.346 +     * is returned (even if this {@code TimeZone} doesn't observe Daylight Saving
  48.347 +     * Time). Otherwise, a Standard Time name is returned.
  48.348 +     *
  48.349 +     * <p>This method is equivalent to:
  48.350 +     * <pre><blockquote>
  48.351 +     * getDisplayName(daylight, style,
  48.352 +     *                Locale.getDefault({@link Locale.Category#DISPLAY}))
  48.353 +     * </blockquote></pre>
  48.354 +     *
  48.355 +     * @param daylight {@code true} specifying a Daylight Saving Time name, or
  48.356 +     *                 {@code false} specifying a Standard Time name
  48.357 +     * @param style either {@link #LONG} or {@link #SHORT}
  48.358 +     * @return the human-readable name of this time zone in the default locale.
  48.359 +     * @exception IllegalArgumentException if {@code style} is invalid.
  48.360 +     * @since 1.2
  48.361 +     * @see #getDisplayName(boolean, int, Locale)
  48.362 +     * @see Locale#getDefault(Locale.Category)
  48.363 +     * @see Locale.Category
  48.364 +     * @see java.text.DateFormatSymbols#getZoneStrings()
  48.365 +     */
  48.366 +    public final String getDisplayName(boolean daylight, int style) {
  48.367 +        return getDisplayName(daylight, style,
  48.368 +                              Locale.getDefault(Locale.Category.DISPLAY));
  48.369 +    }
  48.370 +
  48.371 +    /**
  48.372 +     * Returns a name in the specified {@code style} of this {@code TimeZone}
  48.373 +     * suitable for presentation to the user in the specified {@code
  48.374 +     * locale}. If the specified {@code daylight} is {@code true}, a Daylight
  48.375 +     * Saving Time name is returned (even if this {@code TimeZone} doesn't
  48.376 +     * observe Daylight Saving Time). Otherwise, a Standard Time name is
  48.377 +     * returned.
  48.378 +     *
  48.379 +     * <p>When looking up a time zone name, the {@linkplain
  48.380 +     * ResourceBundle.Control#getCandidateLocales(String,Locale) default
  48.381 +     * <code>Locale</code> search path of <code>ResourceBundle</code>} derived
  48.382 +     * from the specified {@code locale} is used. (No {@linkplain
  48.383 +     * ResourceBundle.Control#getFallbackLocale(String,Locale) fallback
  48.384 +     * <code>Locale</code>} search is performed.) If a time zone name in any
  48.385 +     * {@code Locale} of the search path, including {@link Locale#ROOT}, is
  48.386 +     * found, the name is returned. Otherwise, a string in the
  48.387 +     * <a href="#NormalizedCustomID">normalized custom ID format</a> is returned.
  48.388 +     *
  48.389 +     * @param daylight {@code true} specifying a Daylight Saving Time name, or
  48.390 +     *                 {@code false} specifying a Standard Time name
  48.391 +     * @param style either {@link #LONG} or {@link #SHORT}
  48.392 +     * @param locale   the locale in which to supply the display name.
  48.393 +     * @return the human-readable name of this time zone in the given locale.
  48.394 +     * @exception IllegalArgumentException if {@code style} is invalid.
  48.395 +     * @exception NullPointerException if {@code locale} is {@code null}.
  48.396 +     * @since 1.2
  48.397 +     * @see java.text.DateFormatSymbols#getZoneStrings()
  48.398 +     */
  48.399 +    public String getDisplayName(boolean daylight, int style, Locale locale) {
  48.400 +        if (style != SHORT && style != LONG) {
  48.401 +            throw new IllegalArgumentException("Illegal style: " + style);
  48.402 +        }
  48.403 +
  48.404 +        String id = getID();
  48.405 +        String[] names = getDisplayNames(id, locale);
  48.406 +        if (names == null) {
  48.407 +            if (id.startsWith("GMT")) {
  48.408 +                char sign = id.charAt(3);
  48.409 +                if (sign == '+' || sign == '-') {
  48.410 +                    return id;
  48.411 +                }
  48.412 +            }
  48.413 +            int offset = getRawOffset();
  48.414 +            if (daylight) {
  48.415 +                offset += getDSTSavings();
  48.416 +            }
  48.417 +            return ZoneInfoFile.toCustomID(offset);
  48.418 +        }
  48.419 +
  48.420 +        int index = daylight ? 3 : 1;
  48.421 +        if (style == SHORT) {
  48.422 +            index++;
  48.423 +        }
  48.424 +        return names[index];
  48.425 +    }
  48.426 +
  48.427 +    private static class DisplayNames {
  48.428 +        // Cache for managing display names per timezone per locale
  48.429 +        // The structure is:
  48.430 +        //   Map(key=id, value=SoftReference(Map(key=locale, value=displaynames)))
  48.431 +        private static final Map<String, SoftReference<Map<Locale, String[]>>> CACHE =
  48.432 +            new ConcurrentHashMap<String, SoftReference<Map<Locale, String[]>>>();
  48.433 +    }
  48.434 +
  48.435 +    private static final String[] getDisplayNames(String id, Locale locale) {
  48.436 +        Map<String, SoftReference<Map<Locale, String[]>>> displayNames = DisplayNames.CACHE;
  48.437 +
  48.438 +        SoftReference<Map<Locale, String[]>> ref = displayNames.get(id);
  48.439 +        if (ref != null) {
  48.440 +            Map<Locale, String[]> perLocale = ref.get();
  48.441 +            if (perLocale != null) {
  48.442 +                String[] names = perLocale.get(locale);
  48.443 +                if (names != null) {
  48.444 +                    return names;
  48.445 +                }
  48.446 +                names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
  48.447 +                if (names != null) {
  48.448 +                    perLocale.put(locale, names);
  48.449 +                }
  48.450 +                return names;
  48.451 +            }
  48.452 +        }
  48.453 +
  48.454 +        String[] names = TimeZoneNameUtility.retrieveDisplayNames(id, locale);
  48.455 +        if (names != null) {
  48.456 +            Map<Locale, String[]> perLocale = new ConcurrentHashMap<Locale, String[]>();
  48.457 +            perLocale.put(locale, names);
  48.458 +            ref = new SoftReference<Map<Locale, String[]>>(perLocale);
  48.459 +            displayNames.put(id, ref);
  48.460 +        }
  48.461 +        return names;
  48.462 +    }
  48.463 +
  48.464 +    /**
  48.465 +     * Returns the amount of time to be added to local standard time
  48.466 +     * to get local wall clock time.
  48.467 +     *
  48.468 +     * <p>The default implementation returns 3600000 milliseconds
  48.469 +     * (i.e., one hour) if a call to {@link #useDaylightTime()}
  48.470 +     * returns {@code true}. Otherwise, 0 (zero) is returned.
  48.471 +     *
  48.472 +     * <p>If an underlying {@code TimeZone} implementation subclass
  48.473 +     * supports historical and future Daylight Saving Time schedule
  48.474 +     * changes, this method returns the amount of saving time of the
  48.475 +     * last known Daylight Saving Time rule that can be a future
  48.476 +     * prediction.
  48.477 +     *
  48.478 +     * <p>If the amount of saving time at any given time stamp is
  48.479 +     * required, construct a {@link Calendar} with this {@code
  48.480 +     * TimeZone} and the time stamp, and call {@link Calendar#get(int)
  48.481 +     * Calendar.get}{@code (}{@link Calendar#DST_OFFSET}{@code )}.
  48.482 +     *
  48.483 +     * @return the amount of saving time in milliseconds
  48.484 +     * @since 1.4
  48.485 +     * @see #inDaylightTime(Date)
  48.486 +     * @see #getOffset(long)
  48.487 +     * @see #getOffset(int,int,int,int,int,int)
  48.488 +     * @see Calendar#ZONE_OFFSET
  48.489 +     */
  48.490 +    public int getDSTSavings() {
  48.491 +        if (useDaylightTime()) {
  48.492 +            return 3600000;
  48.493 +        }
  48.494 +        return 0;
  48.495 +    }
  48.496 +
  48.497 +    /**
  48.498 +     * Queries if this {@code TimeZone} uses Daylight Saving Time.
  48.499 +     *
  48.500 +     * <p>If an underlying {@code TimeZone} implementation subclass
  48.501 +     * supports historical and future Daylight Saving Time schedule
  48.502 +     * changes, this method refers to the last known Daylight Saving Time
  48.503 +     * rule that can be a future prediction and may not be the same as
  48.504 +     * the current rule. Consider calling {@link #observesDaylightTime()}
  48.505 +     * if the current rule should also be taken into account.
  48.506 +     *
  48.507 +     * @return {@code true} if this {@code TimeZone} uses Daylight Saving Time,
  48.508 +     *         {@code false}, otherwise.
  48.509 +     * @see #inDaylightTime(Date)
  48.510 +     * @see Calendar#DST_OFFSET
  48.511 +     */
  48.512 +    public abstract boolean useDaylightTime();
  48.513 +
  48.514 +    /**
  48.515 +     * Returns {@code true} if this {@code TimeZone} is currently in
  48.516 +     * Daylight Saving Time, or if a transition from Standard Time to
  48.517 +     * Daylight Saving Time occurs at any future time.
  48.518 +     *
  48.519 +     * <p>The default implementation returns {@code true} if
  48.520 +     * {@code useDaylightTime()} or {@code inDaylightTime(new Date())}
  48.521 +     * returns {@code true}.
  48.522 +     *
  48.523 +     * @return {@code true} if this {@code TimeZone} is currently in
  48.524 +     * Daylight Saving Time, or if a transition from Standard Time to
  48.525 +     * Daylight Saving Time occurs at any future time; {@code false}
  48.526 +     * otherwise.
  48.527 +     * @since 1.7
  48.528 +     * @see #useDaylightTime()
  48.529 +     * @see #inDaylightTime(Date)
  48.530 +     * @see Calendar#DST_OFFSET
  48.531 +     */
  48.532 +    public boolean observesDaylightTime() {
  48.533 +        return useDaylightTime() || inDaylightTime(new Date());
  48.534 +    }
  48.535 +
  48.536 +    /**
  48.537 +     * Queries if the given {@code date} is in Daylight Saving Time in
  48.538 +     * this time zone.
  48.539 +     *
  48.540 +     * @param date the given Date.
  48.541 +     * @return {@code true} if the given date is in Daylight Saving Time,
  48.542 +     *         {@code false}, otherwise.
  48.543 +     */
  48.544 +    abstract public boolean inDaylightTime(Date date);
  48.545 +
  48.546 +    /**
  48.547 +     * Gets the <code>TimeZone</code> for the given ID.
  48.548 +     *
  48.549 +     * @param ID the ID for a <code>TimeZone</code>, either an abbreviation
  48.550 +     * such as "PST", a full name such as "America/Los_Angeles", or a custom
  48.551 +     * ID such as "GMT-8:00". Note that the support of abbreviations is
  48.552 +     * for JDK 1.1.x compatibility only and full names should be used.
  48.553 +     *
  48.554 +     * @return the specified <code>TimeZone</code>, or the GMT zone if the given ID
  48.555 +     * cannot be understood.
  48.556 +     */
  48.557 +    public static synchronized TimeZone getTimeZone(String ID) {
  48.558 +        return getTimeZone(ID, true);
  48.559 +    }
  48.560 +
  48.561 +    private static TimeZone getTimeZone(String ID, boolean fallback) {
  48.562 +        TimeZone tz = ZoneInfo.getTimeZone(ID);
  48.563 +        if (tz == null) {
  48.564 +            tz = parseCustomTimeZone(ID);
  48.565 +            if (tz == null && fallback) {
  48.566 +                tz = new ZoneInfo(GMT_ID, 0);
  48.567 +            }
  48.568 +        }
  48.569 +        return tz;
  48.570 +    }
  48.571 +
  48.572 +    /**
  48.573 +     * Gets the available IDs according to the given time zone offset in milliseconds.
  48.574 +     *
  48.575 +     * @param rawOffset the given time zone GMT offset in milliseconds.
  48.576 +     * @return an array of IDs, where the time zone for that ID has
  48.577 +     * the specified GMT offset. For example, "America/Phoenix" and "America/Denver"
  48.578 +     * both have GMT-07:00, but differ in daylight saving behavior.
  48.579 +     * @see #getRawOffset()
  48.580 +     */
  48.581 +    public static synchronized String[] getAvailableIDs(int rawOffset) {
  48.582 +        return ZoneInfo.getAvailableIDs(rawOffset);
  48.583 +    }
  48.584 +
  48.585 +    /**
  48.586 +     * Gets all the available IDs supported.
  48.587 +     * @return an array of IDs.
  48.588 +     */
  48.589 +    public static synchronized String[] getAvailableIDs() {
  48.590 +        return ZoneInfo.getAvailableIDs();
  48.591 +    }
  48.592 +
  48.593 +    /**
  48.594 +     * Gets the platform defined TimeZone ID.
  48.595 +     **/
  48.596 +    private static native String getSystemTimeZoneID(String javaHome,
  48.597 +                                                     String country);
  48.598 +
  48.599 +    /**
  48.600 +     * Gets the custom time zone ID based on the GMT offset of the
  48.601 +     * platform. (e.g., "GMT+08:00")
  48.602 +     */
  48.603 +    private static native String getSystemGMTOffsetID();
  48.604 +
  48.605 +    /**
  48.606 +     * Gets the default <code>TimeZone</code> for this host.
  48.607 +     * The source of the default <code>TimeZone</code>
  48.608 +     * may vary with implementation.
  48.609 +     * @return a default <code>TimeZone</code>.
  48.610 +     * @see #setDefault
  48.611 +     */
  48.612 +    public static TimeZone getDefault() {
  48.613 +        return (TimeZone) getDefaultRef().clone();
  48.614 +    }
  48.615 +
  48.616 +    /**
  48.617 +     * Returns the reference to the default TimeZone object. This
  48.618 +     * method doesn't create a clone.
  48.619 +     */
  48.620 +    static TimeZone getDefaultRef() {
  48.621 +        TimeZone defaultZone = defaultZoneTL.get();
  48.622 +        if (defaultZone == null) {
  48.623 +            defaultZone = defaultTimeZone;
  48.624 +            if (defaultZone == null) {
  48.625 +                // Need to initialize the default time zone.
  48.626 +                defaultZone = setDefaultZone();
  48.627 +                assert defaultZone != null;
  48.628 +            }
  48.629 +        }
  48.630 +        // Don't clone here.
  48.631 +        return defaultZone;
  48.632 +    }
  48.633 +
  48.634 +    private static synchronized TimeZone setDefaultZone() {
  48.635 +        TimeZone tz = null;
  48.636 +        // get the time zone ID from the system properties
  48.637 +        String zoneID = AccessController.doPrivileged(
  48.638 +                new GetPropertyAction("user.timezone"));
  48.639 +
  48.640 +        // if the time zone ID is not set (yet), perform the
  48.641 +        // platform to Java time zone ID mapping.
  48.642 +        if (zoneID == null || zoneID.equals("")) {
  48.643 +            String country = AccessController.doPrivileged(
  48.644 +                    new GetPropertyAction("user.country"));
  48.645 +            String javaHome = AccessController.doPrivileged(
  48.646 +                    new GetPropertyAction("java.home"));
  48.647 +            try {
  48.648 +                zoneID = getSystemTimeZoneID(javaHome, country);
  48.649 +                if (zoneID == null) {
  48.650 +                    zoneID = GMT_ID;
  48.651 +                }
  48.652 +            } catch (NullPointerException e) {
  48.653 +                zoneID = GMT_ID;
  48.654 +            }
  48.655 +        }
  48.656 +
  48.657 +        // Get the time zone for zoneID. But not fall back to
  48.658 +        // "GMT" here.
  48.659 +        tz = getTimeZone(zoneID, false);
  48.660 +
  48.661 +        if (tz == null) {
  48.662 +            // If the given zone ID is unknown in Java, try to
  48.663 +            // get the GMT-offset-based time zone ID,
  48.664 +            // a.k.a. custom time zone ID (e.g., "GMT-08:00").
  48.665 +            String gmtOffsetID = getSystemGMTOffsetID();
  48.666 +            if (gmtOffsetID != null) {
  48.667 +                zoneID = gmtOffsetID;
  48.668 +            }
  48.669 +            tz = getTimeZone(zoneID, true);
  48.670 +        }
  48.671 +        assert tz != null;
  48.672 +
  48.673 +        final String id = zoneID;
  48.674 +        AccessController.doPrivileged(new PrivilegedAction<Object>() {
  48.675 +                public Object run() {
  48.676 +                    System.setProperty("user.timezone", id);
  48.677 +                    return null;
  48.678 +                }
  48.679 +            });
  48.680 +
  48.681 +        defaultTimeZone = tz;
  48.682 +        return tz;
  48.683 +    }
  48.684 +
  48.685 +    private static boolean hasPermission() {
  48.686 +        boolean hasPermission = true;
  48.687 +        SecurityManager sm = System.getSecurityManager();
  48.688 +        if (sm != null) {
  48.689 +            try {
  48.690 +                sm.checkPermission(new PropertyPermission
  48.691 +                                   ("user.timezone", "write"));
  48.692 +            } catch (SecurityException e) {
  48.693 +                hasPermission = false;
  48.694 +            }
  48.695 +        }
  48.696 +        return hasPermission;
  48.697 +    }
  48.698 +
  48.699 +    /**
  48.700 +     * Sets the <code>TimeZone</code> that is
  48.701 +     * returned by the <code>getDefault</code> method.  If <code>zone</code>
  48.702 +     * is null, reset the default to the value it had originally when the
  48.703 +     * VM first started.
  48.704 +     * @param zone the new default time zone
  48.705 +     * @see #getDefault
  48.706 +     */
  48.707 +    public static void setDefault(TimeZone zone)
  48.708 +    {
  48.709 +        if (hasPermission()) {
  48.710 +            synchronized (TimeZone.class) {
  48.711 +                defaultTimeZone = zone;
  48.712 +                defaultZoneTL.set(null);
  48.713 +            }
  48.714 +        } else {
  48.715 +            defaultZoneTL.set(zone);
  48.716 +        }
  48.717 +    }
  48.718 +
  48.719 +    /**
  48.720 +     * Returns true if this zone has the same rule and offset as another zone.
  48.721 +     * That is, if this zone differs only in ID, if at all.  Returns false
  48.722 +     * if the other zone is null.
  48.723 +     * @param other the <code>TimeZone</code> object to be compared with
  48.724 +     * @return true if the other zone is not null and is the same as this one,
  48.725 +     * with the possible exception of the ID
  48.726 +     * @since 1.2
  48.727 +     */
  48.728 +    public boolean hasSameRules(TimeZone other) {
  48.729 +        return other != null && getRawOffset() == other.getRawOffset() &&
  48.730 +            useDaylightTime() == other.useDaylightTime();
  48.731 +    }
  48.732 +
  48.733 +    /**
  48.734 +     * Creates a copy of this <code>TimeZone</code>.
  48.735 +     *
  48.736 +     * @return a clone of this <code>TimeZone</code>
  48.737 +     */
  48.738 +    public Object clone()
  48.739 +    {
  48.740 +        try {
  48.741 +            TimeZone other = (TimeZone) super.clone();
  48.742 +            other.ID = ID;
  48.743 +            return other;
  48.744 +        } catch (CloneNotSupportedException e) {
  48.745 +            throw new InternalError();
  48.746 +        }
  48.747 +    }
  48.748 +
  48.749 +    /**
  48.750 +     * The null constant as a TimeZone.
  48.751 +     */
  48.752 +    static final TimeZone NO_TIMEZONE = null;
  48.753 +
  48.754 +    // =======================privates===============================
  48.755 +
  48.756 +    /**
  48.757 +     * The string identifier of this <code>TimeZone</code>.  This is a
  48.758 +     * programmatic identifier used internally to look up <code>TimeZone</code>
  48.759 +     * objects from the system table and also to map them to their localized
  48.760 +     * display names.  <code>ID</code> values are unique in the system
  48.761 +     * table but may not be for dynamically created zones.
  48.762 +     * @serial
  48.763 +     */
  48.764 +    private String           ID;
  48.765 +    private static volatile TimeZone defaultTimeZone;
  48.766 +    private static final InheritableThreadLocal<TimeZone> defaultZoneTL
  48.767 +                                        = new InheritableThreadLocal<TimeZone>();
  48.768 +
  48.769 +    static final String         GMT_ID        = "GMT";
  48.770 +    private static final int    GMT_ID_LENGTH = 3;
  48.771 +
  48.772 +    /**
  48.773 +     * Parses a custom time zone identifier and returns a corresponding zone.
  48.774 +     * This method doesn't support the RFC 822 time zone format. (e.g., +hhmm)
  48.775 +     *
  48.776 +     * @param id a string of the <a href="#CustomID">custom ID form</a>.
  48.777 +     * @return a newly created TimeZone with the given offset and
  48.778 +     * no daylight saving time, or null if the id cannot be parsed.
  48.779 +     */
  48.780 +    private static final TimeZone parseCustomTimeZone(String id) {
  48.781 +        int length;
  48.782 +
  48.783 +        // Error if the length of id isn't long enough or id doesn't
  48.784 +        // start with "GMT".
  48.785 +        if ((length = id.length()) < (GMT_ID_LENGTH + 2) ||
  48.786 +            id.indexOf(GMT_ID) != 0) {
  48.787 +            return null;
  48.788 +        }
  48.789 +
  48.790 +        ZoneInfo zi;
  48.791 +
  48.792 +        // First, we try to find it in the cache with the given
  48.793 +        // id. Even the id is not normalized, the returned ZoneInfo
  48.794 +        // should have its normalized id.
  48.795 +        zi = ZoneInfoFile.getZoneInfo(id);
  48.796 +        if (zi != null) {
  48.797 +            return zi;
  48.798 +        }
  48.799 +
  48.800 +        int index = GMT_ID_LENGTH;
  48.801 +        boolean negative = false;
  48.802 +        char c = id.charAt(index++);
  48.803 +        if (c == '-') {
  48.804 +            negative = true;
  48.805 +        } else if (c != '+') {
  48.806 +            return null;
  48.807 +        }
  48.808 +
  48.809 +        int hours = 0;
  48.810 +        int num = 0;
  48.811 +        int countDelim = 0;
  48.812 +        int len = 0;
  48.813 +        while (index < length) {
  48.814 +            c = id.charAt(index++);
  48.815 +            if (c == ':') {
  48.816 +                if (countDelim > 0) {
  48.817 +                    return null;
  48.818 +                }
  48.819 +                if (len > 2) {
  48.820 +                    return null;
  48.821 +                }
  48.822 +                hours = num;
  48.823 +                countDelim++;
  48.824 +                num = 0;
  48.825 +                len = 0;
  48.826 +                continue;
  48.827 +            }
  48.828 +            if (c < '0' || c > '9') {
  48.829 +                return null;
  48.830 +            }
  48.831 +            num = num * 10 + (c - '0');
  48.832 +            len++;
  48.833 +        }
  48.834 +        if (index != length) {
  48.835 +            return null;
  48.836 +        }
  48.837 +        if (countDelim == 0) {
  48.838 +            if (len <= 2) {
  48.839 +                hours = num;
  48.840 +                num = 0;
  48.841 +            } else {
  48.842 +                hours = num / 100;
  48.843 +                num %= 100;
  48.844 +            }
  48.845 +        } else {
  48.846 +            if (len != 2) {
  48.847 +                return null;
  48.848 +            }
  48.849 +        }
  48.850 +        if (hours > 23 || num > 59) {
  48.851 +            return null;
  48.852 +        }
  48.853 +        int gmtOffset =  (hours * 60 + num) * 60 * 1000;
  48.854 +
  48.855 +        if (gmtOffset == 0) {
  48.856 +            zi = ZoneInfoFile.getZoneInfo(GMT_ID);
  48.857 +            if (negative) {
  48.858 +                zi.setID("GMT-00:00");
  48.859 +            } else {
  48.860 +                zi.setID("GMT+00:00");
  48.861 +            }
  48.862 +        } else {
  48.863 +            zi = ZoneInfoFile.getCustomTimeZone(id, negative ? -gmtOffset : gmtOffset);
  48.864 +        }
  48.865 +        return zi;
  48.866 +    }
  48.867 +}
    49.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    49.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentHashMap.java	Thu Oct 03 15:40:35 2013 +0200
    49.3 @@ -0,0 +1,1522 @@
    49.4 +/*
    49.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    49.6 + *
    49.7 + * This code is free software; you can redistribute it and/or modify it
    49.8 + * under the terms of the GNU General Public License version 2 only, as
    49.9 + * published by the Free Software Foundation.  Oracle designates this
   49.10 + * particular file as subject to the "Classpath" exception as provided
   49.11 + * by Oracle in the LICENSE file that accompanied this code.
   49.12 + *
   49.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   49.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   49.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   49.16 + * version 2 for more details (a copy is included in the LICENSE file that
   49.17 + * accompanied this code).
   49.18 + *
   49.19 + * You should have received a copy of the GNU General Public License version
   49.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   49.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   49.22 + *
   49.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   49.24 + * or visit www.oracle.com if you need additional information or have any
   49.25 + * questions.
   49.26 + */
   49.27 +
   49.28 +/*
   49.29 + * This file is available under and governed by the GNU General Public
   49.30 + * License version 2 only, as published by the Free Software Foundation.
   49.31 + * However, the following notice accompanied the original version of this
   49.32 + * file:
   49.33 + *
   49.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   49.35 + * Expert Group and released to the public domain, as explained at
   49.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   49.37 + */
   49.38 +
   49.39 +package java.util.concurrent;
   49.40 +import java.util.concurrent.locks.*;
   49.41 +import java.util.*;
   49.42 +import java.io.Serializable;
   49.43 +import java.io.IOException;
   49.44 +import java.io.ObjectInputStream;
   49.45 +import java.io.ObjectOutputStream;
   49.46 +
   49.47 +/**
   49.48 + * A hash table supporting full concurrency of retrievals and
   49.49 + * adjustable expected concurrency for updates. This class obeys the
   49.50 + * same functional specification as {@link java.util.Hashtable}, and
   49.51 + * includes versions of methods corresponding to each method of
   49.52 + * <tt>Hashtable</tt>. However, even though all operations are
   49.53 + * thread-safe, retrieval operations do <em>not</em> entail locking,
   49.54 + * and there is <em>not</em> any support for locking the entire table
   49.55 + * in a way that prevents all access.  This class is fully
   49.56 + * interoperable with <tt>Hashtable</tt> in programs that rely on its
   49.57 + * thread safety but not on its synchronization details.
   49.58 + *
   49.59 + * <p> Retrieval operations (including <tt>get</tt>) generally do not
   49.60 + * block, so may overlap with update operations (including
   49.61 + * <tt>put</tt> and <tt>remove</tt>). Retrievals reflect the results
   49.62 + * of the most recently <em>completed</em> update operations holding
   49.63 + * upon their onset.  For aggregate operations such as <tt>putAll</tt>
   49.64 + * and <tt>clear</tt>, concurrent retrievals may reflect insertion or
   49.65 + * removal of only some entries.  Similarly, Iterators and
   49.66 + * Enumerations return elements reflecting the state of the hash table
   49.67 + * at some point at or since the creation of the iterator/enumeration.
   49.68 + * They do <em>not</em> throw {@link ConcurrentModificationException}.
   49.69 + * However, iterators are designed to be used by only one thread at a time.
   49.70 + *
   49.71 + * <p> The allowed concurrency among update operations is guided by
   49.72 + * the optional <tt>concurrencyLevel</tt> constructor argument
   49.73 + * (default <tt>16</tt>), which is used as a hint for internal sizing.  The
   49.74 + * table is internally partitioned to try to permit the indicated
   49.75 + * number of concurrent updates without contention. Because placement
   49.76 + * in hash tables is essentially random, the actual concurrency will
   49.77 + * vary.  Ideally, you should choose a value to accommodate as many
   49.78 + * threads as will ever concurrently modify the table. Using a
   49.79 + * significantly higher value than you need can waste space and time,
   49.80 + * and a significantly lower value can lead to thread contention. But
   49.81 + * overestimates and underestimates within an order of magnitude do
   49.82 + * not usually have much noticeable impact. A value of one is
   49.83 + * appropriate when it is known that only one thread will modify and
   49.84 + * all others will only read. Also, resizing this or any other kind of
   49.85 + * hash table is a relatively slow operation, so, when possible, it is
   49.86 + * a good idea to provide estimates of expected table sizes in
   49.87 + * constructors.
   49.88 + *
   49.89 + * <p>This class and its views and iterators implement all of the
   49.90 + * <em>optional</em> methods of the {@link Map} and {@link Iterator}
   49.91 + * interfaces.
   49.92 + *
   49.93 + * <p> Like {@link Hashtable} but unlike {@link HashMap}, this class
   49.94 + * does <em>not</em> allow <tt>null</tt> to be used as a key or value.
   49.95 + *
   49.96 + * <p>This class is a member of the
   49.97 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
   49.98 + * Java Collections Framework</a>.
   49.99 + *
  49.100 + * @since 1.5
  49.101 + * @author Doug Lea
  49.102 + * @param <K> the type of keys maintained by this map
  49.103 + * @param <V> the type of mapped values
  49.104 + */
  49.105 +public class ConcurrentHashMap<K, V> extends AbstractMap<K, V>
  49.106 +        implements ConcurrentMap<K, V>, Serializable {
  49.107 +    private static final long serialVersionUID = 7249069246763182397L;
  49.108 +
  49.109 +    /*
  49.110 +     * The basic strategy is to subdivide the table among Segments,
  49.111 +     * each of which itself is a concurrently readable hash table.  To
  49.112 +     * reduce footprint, all but one segments are constructed only
  49.113 +     * when first needed (see ensureSegment). To maintain visibility
  49.114 +     * in the presence of lazy construction, accesses to segments as
  49.115 +     * well as elements of segment's table must use volatile access,
  49.116 +     * which is done via Unsafe within methods segmentAt etc
  49.117 +     * below. These provide the functionality of AtomicReferenceArrays
  49.118 +     * but reduce the levels of indirection. Additionally,
  49.119 +     * volatile-writes of table elements and entry "next" fields
  49.120 +     * within locked operations use the cheaper "lazySet" forms of
  49.121 +     * writes (via putOrderedObject) because these writes are always
  49.122 +     * followed by lock releases that maintain sequential consistency
  49.123 +     * of table updates.
  49.124 +     *
  49.125 +     * Historical note: The previous version of this class relied
  49.126 +     * heavily on "final" fields, which avoided some volatile reads at
  49.127 +     * the expense of a large initial footprint.  Some remnants of
  49.128 +     * that design (including forced construction of segment 0) exist
  49.129 +     * to ensure serialization compatibility.
  49.130 +     */
  49.131 +
  49.132 +    /* ---------------- Constants -------------- */
  49.133 +
  49.134 +    /**
  49.135 +     * The default initial capacity for this table,
  49.136 +     * used when not otherwise specified in a constructor.
  49.137 +     */
  49.138 +    static final int DEFAULT_INITIAL_CAPACITY = 16;
  49.139 +
  49.140 +    /**
  49.141 +     * The default load factor for this table, used when not
  49.142 +     * otherwise specified in a constructor.
  49.143 +     */
  49.144 +    static final float DEFAULT_LOAD_FACTOR = 0.75f;
  49.145 +
  49.146 +    /**
  49.147 +     * The default concurrency level for this table, used when not
  49.148 +     * otherwise specified in a constructor.
  49.149 +     */
  49.150 +    static final int DEFAULT_CONCURRENCY_LEVEL = 16;
  49.151 +
  49.152 +    /**
  49.153 +     * The maximum capacity, used if a higher value is implicitly
  49.154 +     * specified by either of the constructors with arguments.  MUST
  49.155 +     * be a power of two <= 1<<30 to ensure that entries are indexable
  49.156 +     * using ints.
  49.157 +     */
  49.158 +    static final int MAXIMUM_CAPACITY = 1 << 30;
  49.159 +
  49.160 +    /**
  49.161 +     * The minimum capacity for per-segment tables.  Must be a power
  49.162 +     * of two, at least two to avoid immediate resizing on next use
  49.163 +     * after lazy construction.
  49.164 +     */
  49.165 +    static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
  49.166 +
  49.167 +    /**
  49.168 +     * The maximum number of segments to allow; used to bound
  49.169 +     * constructor arguments. Must be power of two less than 1 << 24.
  49.170 +     */
  49.171 +    static final int MAX_SEGMENTS = 1 << 16; // slightly conservative
  49.172 +
  49.173 +    /**
  49.174 +     * Number of unsynchronized retries in size and containsValue
  49.175 +     * methods before resorting to locking. This is used to avoid
  49.176 +     * unbounded retries if tables undergo continuous modification
  49.177 +     * which would make it impossible to obtain an accurate result.
  49.178 +     */
  49.179 +    static final int RETRIES_BEFORE_LOCK = 2;
  49.180 +
  49.181 +    /* ---------------- Fields -------------- */
  49.182 +
  49.183 +    /**
  49.184 +     * Mask value for indexing into segments. The upper bits of a
  49.185 +     * key's hash code are used to choose the segment.
  49.186 +     */
  49.187 +    final int segmentMask;
  49.188 +
  49.189 +    /**
  49.190 +     * Shift value for indexing within segments.
  49.191 +     */
  49.192 +    final int segmentShift;
  49.193 +
  49.194 +    /**
  49.195 +     * The segments, each of which is a specialized hash table.
  49.196 +     */
  49.197 +    final Segment<K,V>[] segments;
  49.198 +
  49.199 +    transient Set<K> keySet;
  49.200 +    transient Set<Map.Entry<K,V>> entrySet;
  49.201 +    transient Collection<V> values;
  49.202 +
  49.203 +    /**
  49.204 +     * ConcurrentHashMap list entry. Note that this is never exported
  49.205 +     * out as a user-visible Map.Entry.
  49.206 +     */
  49.207 +    static final class HashEntry<K,V> {
  49.208 +        final int hash;
  49.209 +        final K key;
  49.210 +        volatile V value;
  49.211 +        volatile HashEntry<K,V> next;
  49.212 +
  49.213 +        HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
  49.214 +            this.hash = hash;
  49.215 +            this.key = key;
  49.216 +            this.value = value;
  49.217 +            this.next = next;
  49.218 +        }
  49.219 +
  49.220 +        /**
  49.221 +         * Sets next field with volatile write semantics.  (See above
  49.222 +         * about use of putOrderedObject.)
  49.223 +         */
  49.224 +        final void setNext(HashEntry<K,V> n) {
  49.225 +            UNSAFE.putOrderedObject(this, nextOffset, n);
  49.226 +        }
  49.227 +
  49.228 +        // Unsafe mechanics
  49.229 +        static final sun.misc.Unsafe UNSAFE;
  49.230 +        static final long nextOffset;
  49.231 +        static {
  49.232 +            try {
  49.233 +                UNSAFE = sun.misc.Unsafe.getUnsafe();
  49.234 +                Class k = HashEntry.class;
  49.235 +                nextOffset = UNSAFE.objectFieldOffset
  49.236 +                    (k.getDeclaredField("next"));
  49.237 +            } catch (Exception e) {
  49.238 +                throw new Error(e);
  49.239 +            }
  49.240 +        }
  49.241 +    }
  49.242 +
  49.243 +    /**
  49.244 +     * Gets the ith element of given table (if nonnull) with volatile
  49.245 +     * read semantics. Note: This is manually integrated into a few
  49.246 +     * performance-sensitive methods to reduce call overhead.
  49.247 +     */
  49.248 +    @SuppressWarnings("unchecked")
  49.249 +    static final <K,V> HashEntry<K,V> entryAt(HashEntry<K,V>[] tab, int i) {
  49.250 +        return (tab == null) ? null :
  49.251 +            (HashEntry<K,V>) UNSAFE.getObjectVolatile
  49.252 +            (tab, ((long)i << TSHIFT) + TBASE);
  49.253 +    }
  49.254 +
  49.255 +    /**
  49.256 +     * Sets the ith element of given table, with volatile write
  49.257 +     * semantics. (See above about use of putOrderedObject.)
  49.258 +     */
  49.259 +    static final <K,V> void setEntryAt(HashEntry<K,V>[] tab, int i,
  49.260 +                                       HashEntry<K,V> e) {
  49.261 +        UNSAFE.putOrderedObject(tab, ((long)i << TSHIFT) + TBASE, e);
  49.262 +    }
  49.263 +
  49.264 +    /**
  49.265 +     * Applies a supplemental hash function to a given hashCode, which
  49.266 +     * defends against poor quality hash functions.  This is critical
  49.267 +     * because ConcurrentHashMap uses power-of-two length hash tables,
  49.268 +     * that otherwise encounter collisions for hashCodes that do not
  49.269 +     * differ in lower or upper bits.
  49.270 +     */
  49.271 +    private static int hash(int h) {
  49.272 +        // Spread bits to regularize both segment and index locations,
  49.273 +        // using variant of single-word Wang/Jenkins hash.
  49.274 +        h += (h <<  15) ^ 0xffffcd7d;
  49.275 +        h ^= (h >>> 10);
  49.276 +        h += (h <<   3);
  49.277 +        h ^= (h >>>  6);
  49.278 +        h += (h <<   2) + (h << 14);
  49.279 +        return h ^ (h >>> 16);
  49.280 +    }
  49.281 +
  49.282 +    /**
  49.283 +     * Segments are specialized versions of hash tables.  This
  49.284 +     * subclasses from ReentrantLock opportunistically, just to
  49.285 +     * simplify some locking and avoid separate construction.
  49.286 +     */
  49.287 +    static final class Segment<K,V> extends ReentrantLock implements Serializable {
  49.288 +        /*
  49.289 +         * Segments maintain a table of entry lists that are always
  49.290 +         * kept in a consistent state, so can be read (via volatile
  49.291 +         * reads of segments and tables) without locking.  This
  49.292 +         * requires replicating nodes when necessary during table
  49.293 +         * resizing, so the old lists can be traversed by readers
  49.294 +         * still using old version of table.
  49.295 +         *
  49.296 +         * This class defines only mutative methods requiring locking.
  49.297 +         * Except as noted, the methods of this class perform the
  49.298 +         * per-segment versions of ConcurrentHashMap methods.  (Other
  49.299 +         * methods are integrated directly into ConcurrentHashMap
  49.300 +         * methods.) These mutative methods use a form of controlled
  49.301 +         * spinning on contention via methods scanAndLock and
  49.302 +         * scanAndLockForPut. These intersperse tryLocks with
  49.303 +         * traversals to locate nodes.  The main benefit is to absorb
  49.304 +         * cache misses (which are very common for hash tables) while
  49.305 +         * obtaining locks so that traversal is faster once
  49.306 +         * acquired. We do not actually use the found nodes since they
  49.307 +         * must be re-acquired under lock anyway to ensure sequential
  49.308 +         * consistency of updates (and in any case may be undetectably
  49.309 +         * stale), but they will normally be much faster to re-locate.
  49.310 +         * Also, scanAndLockForPut speculatively creates a fresh node
  49.311 +         * to use in put if no node is found.
  49.312 +         */
  49.313 +
  49.314 +        private static final long serialVersionUID = 2249069246763182397L;
  49.315 +
  49.316 +        /**
  49.317 +         * The maximum number of times to tryLock in a prescan before
  49.318 +         * possibly blocking on acquire in preparation for a locked
  49.319 +         * segment operation. On multiprocessors, using a bounded
  49.320 +         * number of retries maintains cache acquired while locating
  49.321 +         * nodes.
  49.322 +         */
  49.323 +        static final int MAX_SCAN_RETRIES =
  49.324 +            Runtime.getRuntime().availableProcessors() > 1 ? 64 : 1;
  49.325 +
  49.326 +        /**
  49.327 +         * The per-segment table. Elements are accessed via
  49.328 +         * entryAt/setEntryAt providing volatile semantics.
  49.329 +         */
  49.330 +        transient volatile HashEntry<K,V>[] table;
  49.331 +
  49.332 +        /**
  49.333 +         * The number of elements. Accessed only either within locks
  49.334 +         * or among other volatile reads that maintain visibility.
  49.335 +         */
  49.336 +        transient int count;
  49.337 +
  49.338 +        /**
  49.339 +         * The total number of mutative operations in this segment.
  49.340 +         * Even though this may overflows 32 bits, it provides
  49.341 +         * sufficient accuracy for stability checks in CHM isEmpty()
  49.342 +         * and size() methods.  Accessed only either within locks or
  49.343 +         * among other volatile reads that maintain visibility.
  49.344 +         */
  49.345 +        transient int modCount;
  49.346 +
  49.347 +        /**
  49.348 +         * The table is rehashed when its size exceeds this threshold.
  49.349 +         * (The value of this field is always <tt>(int)(capacity *
  49.350 +         * loadFactor)</tt>.)
  49.351 +         */
  49.352 +        transient int threshold;
  49.353 +
  49.354 +        /**
  49.355 +         * The load factor for the hash table.  Even though this value
  49.356 +         * is same for all segments, it is replicated to avoid needing
  49.357 +         * links to outer object.
  49.358 +         * @serial
  49.359 +         */
  49.360 +        final float loadFactor;
  49.361 +
  49.362 +        Segment(float lf, int threshold, HashEntry<K,V>[] tab) {
  49.363 +            this.loadFactor = lf;
  49.364 +            this.threshold = threshold;
  49.365 +            this.table = tab;
  49.366 +        }
  49.367 +
  49.368 +        final V put(K key, int hash, V value, boolean onlyIfAbsent) {
  49.369 +            HashEntry<K,V> node = tryLock() ? null :
  49.370 +                scanAndLockForPut(key, hash, value);
  49.371 +            V oldValue;
  49.372 +            try {
  49.373 +                HashEntry<K,V>[] tab = table;
  49.374 +                int index = (tab.length - 1) & hash;
  49.375 +                HashEntry<K,V> first = entryAt(tab, index);
  49.376 +                for (HashEntry<K,V> e = first;;) {
  49.377 +                    if (e != null) {
  49.378 +                        K k;
  49.379 +                        if ((k = e.key) == key ||
  49.380 +                            (e.hash == hash && key.equals(k))) {
  49.381 +                            oldValue = e.value;
  49.382 +                            if (!onlyIfAbsent) {
  49.383 +                                e.value = value;
  49.384 +                                ++modCount;
  49.385 +                            }
  49.386 +                            break;
  49.387 +                        }
  49.388 +                        e = e.next;
  49.389 +                    }
  49.390 +                    else {
  49.391 +                        if (node != null)
  49.392 +                            node.setNext(first);
  49.393 +                        else
  49.394 +                            node = new HashEntry<K,V>(hash, key, value, first);
  49.395 +                        int c = count + 1;
  49.396 +                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)
  49.397 +                            rehash(node);
  49.398 +                        else
  49.399 +                            setEntryAt(tab, index, node);
  49.400 +                        ++modCount;
  49.401 +                        count = c;
  49.402 +                        oldValue = null;
  49.403 +                        break;
  49.404 +                    }
  49.405 +                }
  49.406 +            } finally {
  49.407 +                unlock();
  49.408 +            }
  49.409 +            return oldValue;
  49.410 +        }
  49.411 +
  49.412 +        /**
  49.413 +         * Doubles size of table and repacks entries, also adding the
  49.414 +         * given node to new table
  49.415 +         */
  49.416 +        @SuppressWarnings("unchecked")
  49.417 +        private void rehash(HashEntry<K,V> node) {
  49.418 +            /*
  49.419 +             * Reclassify nodes in each list to new table.  Because we
  49.420 +             * are using power-of-two expansion, the elements from
  49.421 +             * each bin must either stay at same index, or move with a
  49.422 +             * power of two offset. We eliminate unnecessary node
  49.423 +             * creation by catching cases where old nodes can be
  49.424 +             * reused because their next fields won't change.
  49.425 +             * Statistically, at the default threshold, only about
  49.426 +             * one-sixth of them need cloning when a table
  49.427 +             * doubles. The nodes they replace will be garbage
  49.428 +             * collectable as soon as they are no longer referenced by
  49.429 +             * any reader thread that may be in the midst of
  49.430 +             * concurrently traversing table. Entry accesses use plain
  49.431 +             * array indexing because they are followed by volatile
  49.432 +             * table write.
  49.433 +             */
  49.434 +            HashEntry<K,V>[] oldTable = table;
  49.435 +            int oldCapacity = oldTable.length;
  49.436 +            int newCapacity = oldCapacity << 1;
  49.437 +            threshold = (int)(newCapacity * loadFactor);
  49.438 +            HashEntry<K,V>[] newTable =
  49.439 +                (HashEntry<K,V>[]) new HashEntry[newCapacity];
  49.440 +            int sizeMask = newCapacity - 1;
  49.441 +            for (int i = 0; i < oldCapacity ; i++) {
  49.442 +                HashEntry<K,V> e = oldTable[i];
  49.443 +                if (e != null) {
  49.444 +                    HashEntry<K,V> next = e.next;
  49.445 +                    int idx = e.hash & sizeMask;
  49.446 +                    if (next == null)   //  Single node on list
  49.447 +                        newTable[idx] = e;
  49.448 +                    else { // Reuse consecutive sequence at same slot
  49.449 +                        HashEntry<K,V> lastRun = e;
  49.450 +                        int lastIdx = idx;
  49.451 +                        for (HashEntry<K,V> last = next;
  49.452 +                             last != null;
  49.453 +                             last = last.next) {
  49.454 +                            int k = last.hash & sizeMask;
  49.455 +                            if (k != lastIdx) {
  49.456 +                                lastIdx = k;
  49.457 +                                lastRun = last;
  49.458 +                            }
  49.459 +                        }
  49.460 +                        newTable[lastIdx] = lastRun;
  49.461 +                        // Clone remaining nodes
  49.462 +                        for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
  49.463 +                            V v = p.value;
  49.464 +                            int h = p.hash;
  49.465 +                            int k = h & sizeMask;
  49.466 +                            HashEntry<K,V> n = newTable[k];
  49.467 +                            newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
  49.468 +                        }
  49.469 +                    }
  49.470 +                }
  49.471 +            }
  49.472 +            int nodeIndex = node.hash & sizeMask; // add the new node
  49.473 +            node.setNext(newTable[nodeIndex]);
  49.474 +            newTable[nodeIndex] = node;
  49.475 +            table = newTable;
  49.476 +        }
  49.477 +
  49.478 +        /**
  49.479 +         * Scans for a node containing given key while trying to
  49.480 +         * acquire lock, creating and returning one if not found. Upon
  49.481 +         * return, guarantees that lock is held. UNlike in most
  49.482 +         * methods, calls to method equals are not screened: Since
  49.483 +         * traversal speed doesn't matter, we might as well help warm
  49.484 +         * up the associated code and accesses as well.
  49.485 +         *
  49.486 +         * @return a new node if key not found, else null
  49.487 +         */
  49.488 +        private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
  49.489 +            HashEntry<K,V> first = entryForHash(this, hash);
  49.490 +            HashEntry<K,V> e = first;
  49.491 +            HashEntry<K,V> node = null;
  49.492 +            int retries = -1; // negative while locating node
  49.493 +            while (!tryLock()) {
  49.494 +                HashEntry<K,V> f; // to recheck first below
  49.495 +                if (retries < 0) {
  49.496 +                    if (e == null) {
  49.497 +                        if (node == null) // speculatively create node
  49.498 +                            node = new HashEntry<K,V>(hash, key, value, null);
  49.499 +                        retries = 0;
  49.500 +                    }
  49.501 +                    else if (key.equals(e.key))
  49.502 +                        retries = 0;
  49.503 +                    else
  49.504 +                        e = e.next;
  49.505 +                }
  49.506 +                else if (++retries > MAX_SCAN_RETRIES) {
  49.507 +                    lock();
  49.508 +                    break;
  49.509 +                }
  49.510 +                else if ((retries & 1) == 0 &&
  49.511 +                         (f = entryForHash(this, hash)) != first) {
  49.512 +                    e = first = f; // re-traverse if entry changed
  49.513 +                    retries = -1;
  49.514 +                }
  49.515 +            }
  49.516 +            return node;
  49.517 +        }
  49.518 +
  49.519 +        /**
  49.520 +         * Scans for a node containing the given key while trying to
  49.521 +         * acquire lock for a remove or replace operation. Upon
  49.522 +         * return, guarantees that lock is held.  Note that we must
  49.523 +         * lock even if the key is not found, to ensure sequential
  49.524 +         * consistency of updates.
  49.525 +         */
  49.526 +        private void scanAndLock(Object key, int hash) {
  49.527 +            // similar to but simpler than scanAndLockForPut
  49.528 +            HashEntry<K,V> first = entryForHash(this, hash);
  49.529 +            HashEntry<K,V> e = first;
  49.530 +            int retries = -1;
  49.531 +            while (!tryLock()) {
  49.532 +                HashEntry<K,V> f;
  49.533 +                if (retries < 0) {
  49.534 +                    if (e == null || key.equals(e.key))
  49.535 +                        retries = 0;
  49.536 +                    else
  49.537 +                        e = e.next;
  49.538 +                }
  49.539 +                else if (++retries > MAX_SCAN_RETRIES) {
  49.540 +                    lock();
  49.541 +                    break;
  49.542 +                }
  49.543 +                else if ((retries & 1) == 0 &&
  49.544 +                         (f = entryForHash(this, hash)) != first) {
  49.545 +                    e = first = f;
  49.546 +                    retries = -1;
  49.547 +                }
  49.548 +            }
  49.549 +        }
  49.550 +
  49.551 +        /**
  49.552 +         * Remove; match on key only if value null, else match both.
  49.553 +         */
  49.554 +        final V remove(Object key, int hash, Object value) {
  49.555 +            if (!tryLock())
  49.556 +                scanAndLock(key, hash);
  49.557 +            V oldValue = null;
  49.558 +            try {
  49.559 +                HashEntry<K,V>[] tab = table;
  49.560 +                int index = (tab.length - 1) & hash;
  49.561 +                HashEntry<K,V> e = entryAt(tab, index);
  49.562 +                HashEntry<K,V> pred = null;
  49.563 +                while (e != null) {
  49.564 +                    K k;
  49.565 +                    HashEntry<K,V> next = e.next;
  49.566 +                    if ((k = e.key) == key ||
  49.567 +                        (e.hash == hash && key.equals(k))) {
  49.568 +                        V v = e.value;
  49.569 +                        if (value == null || value == v || value.equals(v)) {
  49.570 +                            if (pred == null)
  49.571 +                                setEntryAt(tab, index, next);
  49.572 +                            else
  49.573 +                                pred.setNext(next);
  49.574 +                            ++modCount;
  49.575 +                            --count;
  49.576 +                            oldValue = v;
  49.577 +                        }
  49.578 +                        break;
  49.579 +                    }
  49.580 +                    pred = e;
  49.581 +                    e = next;
  49.582 +                }
  49.583 +            } finally {
  49.584 +                unlock();
  49.585 +            }
  49.586 +            return oldValue;
  49.587 +        }
  49.588 +
  49.589 +        final boolean replace(K key, int hash, V oldValue, V newValue) {
  49.590 +            if (!tryLock())
  49.591 +                scanAndLock(key, hash);
  49.592 +            boolean replaced = false;
  49.593 +            try {
  49.594 +                HashEntry<K,V> e;
  49.595 +                for (e = entryForHash(this, hash); e != null; e = e.next) {
  49.596 +                    K k;
  49.597 +                    if ((k = e.key) == key ||
  49.598 +                        (e.hash == hash && key.equals(k))) {
  49.599 +                        if (oldValue.equals(e.value)) {
  49.600 +                            e.value = newValue;
  49.601 +                            ++modCount;
  49.602 +                            replaced = true;
  49.603 +                        }
  49.604 +                        break;
  49.605 +                    }
  49.606 +                }
  49.607 +            } finally {
  49.608 +                unlock();
  49.609 +            }
  49.610 +            return replaced;
  49.611 +        }
  49.612 +
  49.613 +        final V replace(K key, int hash, V value) {
  49.614 +            if (!tryLock())
  49.615 +                scanAndLock(key, hash);
  49.616 +            V oldValue = null;
  49.617 +            try {
  49.618 +                HashEntry<K,V> e;
  49.619 +                for (e = entryForHash(this, hash); e != null; e = e.next) {
  49.620 +                    K k;
  49.621 +                    if ((k = e.key) == key ||
  49.622 +                        (e.hash == hash && key.equals(k))) {
  49.623 +                        oldValue = e.value;
  49.624 +                        e.value = value;
  49.625 +                        ++modCount;
  49.626 +                        break;
  49.627 +                    }
  49.628 +                }
  49.629 +            } finally {
  49.630 +                unlock();
  49.631 +            }
  49.632 +            return oldValue;
  49.633 +        }
  49.634 +
  49.635 +        final void clear() {
  49.636 +            lock();
  49.637 +            try {
  49.638 +                HashEntry<K,V>[] tab = table;
  49.639 +                for (int i = 0; i < tab.length ; i++)
  49.640 +                    setEntryAt(tab, i, null);
  49.641 +                ++modCount;
  49.642 +                count = 0;
  49.643 +            } finally {
  49.644 +                unlock();
  49.645 +            }
  49.646 +        }
  49.647 +    }
  49.648 +
  49.649 +    // Accessing segments
  49.650 +
  49.651 +    /**
  49.652 +     * Gets the jth element of given segment array (if nonnull) with
  49.653 +     * volatile element access semantics via Unsafe. (The null check
  49.654 +     * can trigger harmlessly only during deserialization.) Note:
  49.655 +     * because each element of segments array is set only once (using
  49.656 +     * fully ordered writes), some performance-sensitive methods rely
  49.657 +     * on this method only as a recheck upon null reads.
  49.658 +     */
  49.659 +    @SuppressWarnings("unchecked")
  49.660 +    static final <K,V> Segment<K,V> segmentAt(Segment<K,V>[] ss, int j) {
  49.661 +        long u = (j << SSHIFT) + SBASE;
  49.662 +        return ss == null ? null :
  49.663 +            (Segment<K,V>) UNSAFE.getObjectVolatile(ss, u);
  49.664 +    }
  49.665 +
  49.666 +    /**
  49.667 +     * Returns the segment for the given index, creating it and
  49.668 +     * recording in segment table (via CAS) if not already present.
  49.669 +     *
  49.670 +     * @param k the index
  49.671 +     * @return the segment
  49.672 +     */
  49.673 +    @SuppressWarnings("unchecked")
  49.674 +    private Segment<K,V> ensureSegment(int k) {
  49.675 +        final Segment<K,V>[] ss = this.segments;
  49.676 +        long u = (k << SSHIFT) + SBASE; // raw offset
  49.677 +        Segment<K,V> seg;
  49.678 +        if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
  49.679 +            Segment<K,V> proto = ss[0]; // use segment 0 as prototype
  49.680 +            int cap = proto.table.length;
  49.681 +            float lf = proto.loadFactor;
  49.682 +            int threshold = (int)(cap * lf);
  49.683 +            HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
  49.684 +            if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
  49.685 +                == null) { // recheck
  49.686 +                Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
  49.687 +                while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
  49.688 +                       == null) {
  49.689 +                    if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
  49.690 +                        break;
  49.691 +                }
  49.692 +            }
  49.693 +        }
  49.694 +        return seg;
  49.695 +    }
  49.696 +
  49.697 +    // Hash-based segment and entry accesses
  49.698 +
  49.699 +    /**
  49.700 +     * Get the segment for the given hash
  49.701 +     */
  49.702 +    @SuppressWarnings("unchecked")
  49.703 +    private Segment<K,V> segmentForHash(int h) {
  49.704 +        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
  49.705 +        return (Segment<K,V>) UNSAFE.getObjectVolatile(segments, u);
  49.706 +    }
  49.707 +
  49.708 +    /**
  49.709 +     * Gets the table entry for the given segment and hash
  49.710 +     */
  49.711 +    @SuppressWarnings("unchecked")
  49.712 +    static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
  49.713 +        HashEntry<K,V>[] tab;
  49.714 +        return (seg == null || (tab = seg.table) == null) ? null :
  49.715 +            (HashEntry<K,V>) UNSAFE.getObjectVolatile
  49.716 +            (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
  49.717 +    }
  49.718 +
  49.719 +    /* ---------------- Public operations -------------- */
  49.720 +
  49.721 +    /**
  49.722 +     * Creates a new, empty map with the specified initial
  49.723 +     * capacity, load factor and concurrency level.
  49.724 +     *
  49.725 +     * @param initialCapacity the initial capacity. The implementation
  49.726 +     * performs internal sizing to accommodate this many elements.
  49.727 +     * @param loadFactor  the load factor threshold, used to control resizing.
  49.728 +     * Resizing may be performed when the average number of elements per
  49.729 +     * bin exceeds this threshold.
  49.730 +     * @param concurrencyLevel the estimated number of concurrently
  49.731 +     * updating threads. The implementation performs internal sizing
  49.732 +     * to try to accommodate this many threads.
  49.733 +     * @throws IllegalArgumentException if the initial capacity is
  49.734 +     * negative or the load factor or concurrencyLevel are
  49.735 +     * nonpositive.
  49.736 +     */
  49.737 +    @SuppressWarnings("unchecked")
  49.738 +    public ConcurrentHashMap(int initialCapacity,
  49.739 +                             float loadFactor, int concurrencyLevel) {
  49.740 +        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
  49.741 +            throw new IllegalArgumentException();
  49.742 +        if (concurrencyLevel > MAX_SEGMENTS)
  49.743 +            concurrencyLevel = MAX_SEGMENTS;
  49.744 +        // Find power-of-two sizes best matching arguments
  49.745 +        int sshift = 0;
  49.746 +        int ssize = 1;
  49.747 +        while (ssize < concurrencyLevel) {
  49.748 +            ++sshift;
  49.749 +            ssize <<= 1;
  49.750 +        }
  49.751 +        this.segmentShift = 32 - sshift;
  49.752 +        this.segmentMask = ssize - 1;
  49.753 +        if (initialCapacity > MAXIMUM_CAPACITY)
  49.754 +            initialCapacity = MAXIMUM_CAPACITY;
  49.755 +        int c = initialCapacity / ssize;
  49.756 +        if (c * ssize < initialCapacity)
  49.757 +            ++c;
  49.758 +        int cap = MIN_SEGMENT_TABLE_CAPACITY;
  49.759 +        while (cap < c)
  49.760 +            cap <<= 1;
  49.761 +        // create segments and segments[0]
  49.762 +        Segment<K,V> s0 =
  49.763 +            new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
  49.764 +                             (HashEntry<K,V>[])new HashEntry[cap]);
  49.765 +        Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
  49.766 +        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
  49.767 +        this.segments = ss;
  49.768 +    }
  49.769 +
  49.770 +    /**
  49.771 +     * Creates a new, empty map with the specified initial capacity
  49.772 +     * and load factor and with the default concurrencyLevel (16).
  49.773 +     *
  49.774 +     * @param initialCapacity The implementation performs internal
  49.775 +     * sizing to accommodate this many elements.
  49.776 +     * @param loadFactor  the load factor threshold, used to control resizing.
  49.777 +     * Resizing may be performed when the average number of elements per
  49.778 +     * bin exceeds this threshold.
  49.779 +     * @throws IllegalArgumentException if the initial capacity of
  49.780 +     * elements is negative or the load factor is nonpositive
  49.781 +     *
  49.782 +     * @since 1.6
  49.783 +     */
  49.784 +    public ConcurrentHashMap(int initialCapacity, float loadFactor) {
  49.785 +        this(initialCapacity, loadFactor, DEFAULT_CONCURRENCY_LEVEL);
  49.786 +    }
  49.787 +
  49.788 +    /**
  49.789 +     * Creates a new, empty map with the specified initial capacity,
  49.790 +     * and with default load factor (0.75) and concurrencyLevel (16).
  49.791 +     *
  49.792 +     * @param initialCapacity the initial capacity. The implementation
  49.793 +     * performs internal sizing to accommodate this many elements.
  49.794 +     * @throws IllegalArgumentException if the initial capacity of
  49.795 +     * elements is negative.
  49.796 +     */
  49.797 +    public ConcurrentHashMap(int initialCapacity) {
  49.798 +        this(initialCapacity, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
  49.799 +    }
  49.800 +
  49.801 +    /**
  49.802 +     * Creates a new, empty map with a default initial capacity (16),
  49.803 +     * load factor (0.75) and concurrencyLevel (16).
  49.804 +     */
  49.805 +    public ConcurrentHashMap() {
  49.806 +        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
  49.807 +    }
  49.808 +
  49.809 +    /**
  49.810 +     * Creates a new map with the same mappings as the given map.
  49.811 +     * The map is created with a capacity of 1.5 times the number
  49.812 +     * of mappings in the given map or 16 (whichever is greater),
  49.813 +     * and a default load factor (0.75) and concurrencyLevel (16).
  49.814 +     *
  49.815 +     * @param m the map
  49.816 +     */
  49.817 +    public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
  49.818 +        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
  49.819 +                      DEFAULT_INITIAL_CAPACITY),
  49.820 +             DEFAULT_LOAD_FACTOR, DEFAULT_CONCURRENCY_LEVEL);
  49.821 +        putAll(m);
  49.822 +    }
  49.823 +
  49.824 +    /**
  49.825 +     * Returns <tt>true</tt> if this map contains no key-value mappings.
  49.826 +     *
  49.827 +     * @return <tt>true</tt> if this map contains no key-value mappings
  49.828 +     */
  49.829 +    public boolean isEmpty() {
  49.830 +        /*
  49.831 +         * Sum per-segment modCounts to avoid mis-reporting when
  49.832 +         * elements are concurrently added and removed in one segment
  49.833 +         * while checking another, in which case the table was never
  49.834 +         * actually empty at any point. (The sum ensures accuracy up
  49.835 +         * through at least 1<<31 per-segment modifications before
  49.836 +         * recheck.)  Methods size() and containsValue() use similar
  49.837 +         * constructions for stability checks.
  49.838 +         */
  49.839 +        long sum = 0L;
  49.840 +        final Segment<K,V>[] segments = this.segments;
  49.841 +        for (int j = 0; j < segments.length; ++j) {
  49.842 +            Segment<K,V> seg = segmentAt(segments, j);
  49.843 +            if (seg != null) {
  49.844 +                if (seg.count != 0)
  49.845 +                    return false;
  49.846 +                sum += seg.modCount;
  49.847 +            }
  49.848 +        }
  49.849 +        if (sum != 0L) { // recheck unless no modifications
  49.850 +            for (int j = 0; j < segments.length; ++j) {
  49.851 +                Segment<K,V> seg = segmentAt(segments, j);
  49.852 +                if (seg != null) {
  49.853 +                    if (seg.count != 0)
  49.854 +                        return false;
  49.855 +                    sum -= seg.modCount;
  49.856 +                }
  49.857 +            }
  49.858 +            if (sum != 0L)
  49.859 +                return false;
  49.860 +        }
  49.861 +        return true;
  49.862 +    }
  49.863 +
  49.864 +    /**
  49.865 +     * Returns the number of key-value mappings in this map.  If the
  49.866 +     * map contains more than <tt>Integer.MAX_VALUE</tt> elements, returns
  49.867 +     * <tt>Integer.MAX_VALUE</tt>.
  49.868 +     *
  49.869 +     * @return the number of key-value mappings in this map
  49.870 +     */
  49.871 +    public int size() {
  49.872 +        // Try a few times to get accurate count. On failure due to
  49.873 +        // continuous async changes in table, resort to locking.
  49.874 +        final Segment<K,V>[] segments = this.segments;
  49.875 +        int size;
  49.876 +        boolean overflow; // true if size overflows 32 bits
  49.877 +        long sum;         // sum of modCounts
  49.878 +        long last = 0L;   // previous sum
  49.879 +        int retries = -1; // first iteration isn't retry
  49.880 +        try {
  49.881 +            for (;;) {
  49.882 +                if (retries++ == RETRIES_BEFORE_LOCK) {
  49.883 +                    for (int j = 0; j < segments.length; ++j)
  49.884 +                        ensureSegment(j).lock(); // force creation
  49.885 +                }
  49.886 +                sum = 0L;
  49.887 +                size = 0;
  49.888 +                overflow = false;
  49.889 +                for (int j = 0; j < segments.length; ++j) {
  49.890 +                    Segment<K,V> seg = segmentAt(segments, j);
  49.891 +                    if (seg != null) {
  49.892 +                        sum += seg.modCount;
  49.893 +                        int c = seg.count;
  49.894 +                        if (c < 0 || (size += c) < 0)
  49.895 +                            overflow = true;
  49.896 +                    }
  49.897 +                }
  49.898 +                if (sum == last)
  49.899 +                    break;
  49.900 +                last = sum;
  49.901 +            }
  49.902 +        } finally {
  49.903 +            if (retries > RETRIES_BEFORE_LOCK) {
  49.904 +                for (int j = 0; j < segments.length; ++j)
  49.905 +                    segmentAt(segments, j).unlock();
  49.906 +            }
  49.907 +        }
  49.908 +        return overflow ? Integer.MAX_VALUE : size;
  49.909 +    }
  49.910 +
  49.911 +    /**
  49.912 +     * Returns the value to which the specified key is mapped,
  49.913 +     * or {@code null} if this map contains no mapping for the key.
  49.914 +     *
  49.915 +     * <p>More formally, if this map contains a mapping from a key
  49.916 +     * {@code k} to a value {@code v} such that {@code key.equals(k)},
  49.917 +     * then this method returns {@code v}; otherwise it returns
  49.918 +     * {@code null}.  (There can be at most one such mapping.)
  49.919 +     *
  49.920 +     * @throws NullPointerException if the specified key is null
  49.921 +     */
  49.922 +    public V get(Object key) {
  49.923 +        Segment<K,V> s; // manually integrate access methods to reduce overhead
  49.924 +        HashEntry<K,V>[] tab;
  49.925 +        int h = hash(key.hashCode());
  49.926 +        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
  49.927 +        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
  49.928 +            (tab = s.table) != null) {
  49.929 +            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
  49.930 +                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
  49.931 +                 e != null; e = e.next) {
  49.932 +                K k;
  49.933 +                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
  49.934 +                    return e.value;
  49.935 +            }
  49.936 +        }
  49.937 +        return null;
  49.938 +    }
  49.939 +
  49.940 +    /**
  49.941 +     * Tests if the specified object is a key in this table.
  49.942 +     *
  49.943 +     * @param  key   possible key
  49.944 +     * @return <tt>true</tt> if and only if the specified object
  49.945 +     *         is a key in this table, as determined by the
  49.946 +     *         <tt>equals</tt> method; <tt>false</tt> otherwise.
  49.947 +     * @throws NullPointerException if the specified key is null
  49.948 +     */
  49.949 +    @SuppressWarnings("unchecked")
  49.950 +    public boolean containsKey(Object key) {
  49.951 +        Segment<K,V> s; // same as get() except no need for volatile value read
  49.952 +        HashEntry<K,V>[] tab;
  49.953 +        int h = hash(key.hashCode());
  49.954 +        long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
  49.955 +        if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
  49.956 +            (tab = s.table) != null) {
  49.957 +            for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
  49.958 +                     (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
  49.959 +                 e != null; e = e.next) {
  49.960 +                K k;
  49.961 +                if ((k = e.key) == key || (e.hash == h && key.equals(k)))
  49.962 +                    return true;
  49.963 +            }
  49.964 +        }
  49.965 +        return false;
  49.966 +    }
  49.967 +
  49.968 +    /**
  49.969 +     * Returns <tt>true</tt> if this map maps one or more keys to the
  49.970 +     * specified value. Note: This method requires a full internal
  49.971 +     * traversal of the hash table, and so is much slower than
  49.972 +     * method <tt>containsKey</tt>.
  49.973 +     *
  49.974 +     * @param value value whose presence in this map is to be tested
  49.975 +     * @return <tt>true</tt> if this map maps one or more keys to the
  49.976 +     *         specified value
  49.977 +     * @throws NullPointerException if the specified value is null
  49.978 +     */
  49.979 +    public boolean containsValue(Object value) {
  49.980 +        // Same idea as size()
  49.981 +        if (value == null)
  49.982 +            throw new NullPointerException();
  49.983 +        final Segment<K,V>[] segments = this.segments;
  49.984 +        boolean found = false;
  49.985 +        long last = 0;
  49.986 +        int retries = -1;
  49.987 +        try {
  49.988 +            outer: for (;;) {
  49.989 +                if (retries++ == RETRIES_BEFORE_LOCK) {
  49.990 +                    for (int j = 0; j < segments.length; ++j)
  49.991 +                        ensureSegment(j).lock(); // force creation
  49.992 +                }
  49.993 +                long hashSum = 0L;
  49.994 +                int sum = 0;
  49.995 +                for (int j = 0; j < segments.length; ++j) {
  49.996 +                    HashEntry<K,V>[] tab;
  49.997 +                    Segment<K,V> seg = segmentAt(segments, j);
  49.998 +                    if (seg != null && (tab = seg.table) != null) {
  49.999 +                        for (int i = 0 ; i < tab.length; i++) {
 49.1000 +                            HashEntry<K,V> e;
 49.1001 +                            for (e = entryAt(tab, i); e != null; e = e.next) {
 49.1002 +                                V v = e.value;
 49.1003 +                                if (v != null && value.equals(v)) {
 49.1004 +                                    found = true;
 49.1005 +                                    break outer;
 49.1006 +                                }
 49.1007 +                            }
 49.1008 +                        }
 49.1009 +                        sum += seg.modCount;
 49.1010 +                    }
 49.1011 +                }
 49.1012 +                if (retries > 0 && sum == last)
 49.1013 +                    break;
 49.1014 +                last = sum;
 49.1015 +            }
 49.1016 +        } finally {
 49.1017 +            if (retries > RETRIES_BEFORE_LOCK) {
 49.1018 +                for (int j = 0; j < segments.length; ++j)
 49.1019 +                    segmentAt(segments, j).unlock();
 49.1020 +            }
 49.1021 +        }
 49.1022 +        return found;
 49.1023 +    }
 49.1024 +
 49.1025 +    /**
 49.1026 +     * Legacy method testing if some key maps into the specified value
 49.1027 +     * in this table.  This method is identical in functionality to
 49.1028 +     * {@link #containsValue}, and exists solely to ensure
 49.1029 +     * full compatibility with class {@link java.util.Hashtable},
 49.1030 +     * which supported this method prior to introduction of the
 49.1031 +     * Java Collections framework.
 49.1032 +
 49.1033 +     * @param  value a value to search for
 49.1034 +     * @return <tt>true</tt> if and only if some key maps to the
 49.1035 +     *         <tt>value</tt> argument in this table as
 49.1036 +     *         determined by the <tt>equals</tt> method;
 49.1037 +     *         <tt>false</tt> otherwise
 49.1038 +     * @throws NullPointerException if the specified value is null
 49.1039 +     */
 49.1040 +    public boolean contains(Object value) {
 49.1041 +        return containsValue(value);
 49.1042 +    }
 49.1043 +
 49.1044 +    /**
 49.1045 +     * Maps the specified key to the specified value in this table.
 49.1046 +     * Neither the key nor the value can be null.
 49.1047 +     *
 49.1048 +     * <p> The value can be retrieved by calling the <tt>get</tt> method
 49.1049 +     * with a key that is equal to the original key.
 49.1050 +     *
 49.1051 +     * @param key key with which the specified value is to be associated
 49.1052 +     * @param value value to be associated with the specified key
 49.1053 +     * @return the previous value associated with <tt>key</tt>, or
 49.1054 +     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
 49.1055 +     * @throws NullPointerException if the specified key or value is null
 49.1056 +     */
 49.1057 +    @SuppressWarnings("unchecked")
 49.1058 +    public V put(K key, V value) {
 49.1059 +        Segment<K,V> s;
 49.1060 +        if (value == null)
 49.1061 +            throw new NullPointerException();
 49.1062 +        int hash = hash(key.hashCode());
 49.1063 +        int j = (hash >>> segmentShift) & segmentMask;
 49.1064 +        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
 49.1065 +             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
 49.1066 +            s = ensureSegment(j);
 49.1067 +        return s.put(key, hash, value, false);
 49.1068 +    }
 49.1069 +
 49.1070 +    /**
 49.1071 +     * {@inheritDoc}
 49.1072 +     *
 49.1073 +     * @return the previous value associated with the specified key,
 49.1074 +     *         or <tt>null</tt> if there was no mapping for the key
 49.1075 +     * @throws NullPointerException if the specified key or value is null
 49.1076 +     */
 49.1077 +    @SuppressWarnings("unchecked")
 49.1078 +    public V putIfAbsent(K key, V value) {
 49.1079 +        Segment<K,V> s;
 49.1080 +        if (value == null)
 49.1081 +            throw new NullPointerException();
 49.1082 +        int hash = hash(key.hashCode());
 49.1083 +        int j = (hash >>> segmentShift) & segmentMask;
 49.1084 +        if ((s = (Segment<K,V>)UNSAFE.getObject
 49.1085 +             (segments, (j << SSHIFT) + SBASE)) == null)
 49.1086 +            s = ensureSegment(j);
 49.1087 +        return s.put(key, hash, value, true);
 49.1088 +    }
 49.1089 +
 49.1090 +    /**
 49.1091 +     * Copies all of the mappings from the specified map to this one.
 49.1092 +     * These mappings replace any mappings that this map had for any of the
 49.1093 +     * keys currently in the specified map.
 49.1094 +     *
 49.1095 +     * @param m mappings to be stored in this map
 49.1096 +     */
 49.1097 +    public void putAll(Map<? extends K, ? extends V> m) {
 49.1098 +        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
 49.1099 +            put(e.getKey(), e.getValue());
 49.1100 +    }
 49.1101 +
 49.1102 +    /**
 49.1103 +     * Removes the key (and its corresponding value) from this map.
 49.1104 +     * This method does nothing if the key is not in the map.
 49.1105 +     *
 49.1106 +     * @param  key the key that needs to be removed
 49.1107 +     * @return the previous value associated with <tt>key</tt>, or
 49.1108 +     *         <tt>null</tt> if there was no mapping for <tt>key</tt>
 49.1109 +     * @throws NullPointerException if the specified key is null
 49.1110 +     */
 49.1111 +    public V remove(Object key) {
 49.1112 +        int hash = hash(key.hashCode());
 49.1113 +        Segment<K,V> s = segmentForHash(hash);
 49.1114 +        return s == null ? null : s.remove(key, hash, null);
 49.1115 +    }
 49.1116 +
 49.1117 +    /**
 49.1118 +     * {@inheritDoc}
 49.1119 +     *
 49.1120 +     * @throws NullPointerException if the specified key is null
 49.1121 +     */
 49.1122 +    public boolean remove(Object key, Object value) {
 49.1123 +        int hash = hash(key.hashCode());
 49.1124 +        Segment<K,V> s;
 49.1125 +        return value != null && (s = segmentForHash(hash)) != null &&
 49.1126 +            s.remove(key, hash, value) != null;
 49.1127 +    }
 49.1128 +
 49.1129 +    /**
 49.1130 +     * {@inheritDoc}
 49.1131 +     *
 49.1132 +     * @throws NullPointerException if any of the arguments are null
 49.1133 +     */
 49.1134 +    public boolean replace(K key, V oldValue, V newValue) {
 49.1135 +        int hash = hash(key.hashCode());
 49.1136 +        if (oldValue == null || newValue == null)
 49.1137 +            throw new NullPointerException();
 49.1138 +        Segment<K,V> s = segmentForHash(hash);
 49.1139 +        return s != null && s.replace(key, hash, oldValue, newValue);
 49.1140 +    }
 49.1141 +
 49.1142 +    /**
 49.1143 +     * {@inheritDoc}
 49.1144 +     *
 49.1145 +     * @return the previous value associated with the specified key,
 49.1146 +     *         or <tt>null</tt> if there was no mapping for the key
 49.1147 +     * @throws NullPointerException if the specified key or value is null
 49.1148 +     */
 49.1149 +    public V replace(K key, V value) {
 49.1150 +        int hash = hash(key.hashCode());
 49.1151 +        if (value == null)
 49.1152 +            throw new NullPointerException();
 49.1153 +        Segment<K,V> s = segmentForHash(hash);
 49.1154 +        return s == null ? null : s.replace(key, hash, value);
 49.1155 +    }
 49.1156 +
 49.1157 +    /**
 49.1158 +     * Removes all of the mappings from this map.
 49.1159 +     */
 49.1160 +    public void clear() {
 49.1161 +        final Segment<K,V>[] segments = this.segments;
 49.1162 +        for (int j = 0; j < segments.length; ++j) {
 49.1163 +            Segment<K,V> s = segmentAt(segments, j);
 49.1164 +            if (s != null)
 49.1165 +                s.clear();
 49.1166 +        }
 49.1167 +    }
 49.1168 +
 49.1169 +    /**
 49.1170 +     * Returns a {@link Set} view of the keys contained in this map.
 49.1171 +     * The set is backed by the map, so changes to the map are
 49.1172 +     * reflected in the set, and vice-versa.  The set supports element
 49.1173 +     * removal, which removes the corresponding mapping from this map,
 49.1174 +     * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
 49.1175 +     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
 49.1176 +     * operations.  It does not support the <tt>add</tt> or
 49.1177 +     * <tt>addAll</tt> operations.
 49.1178 +     *
 49.1179 +     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
 49.1180 +     * that will never throw {@link ConcurrentModificationException},
 49.1181 +     * and guarantees to traverse elements as they existed upon
 49.1182 +     * construction of the iterator, and may (but is not guaranteed to)
 49.1183 +     * reflect any modifications subsequent to construction.
 49.1184 +     */
 49.1185 +    public Set<K> keySet() {
 49.1186 +        Set<K> ks = keySet;
 49.1187 +        return (ks != null) ? ks : (keySet = new KeySet());
 49.1188 +    }
 49.1189 +
 49.1190 +    /**
 49.1191 +     * Returns a {@link Collection} view of the values contained in this map.
 49.1192 +     * The collection is backed by the map, so changes to the map are
 49.1193 +     * reflected in the collection, and vice-versa.  The collection
 49.1194 +     * supports element removal, which removes the corresponding
 49.1195 +     * mapping from this map, via the <tt>Iterator.remove</tt>,
 49.1196 +     * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
 49.1197 +     * <tt>retainAll</tt>, and <tt>clear</tt> operations.  It does not
 49.1198 +     * support the <tt>add</tt> or <tt>addAll</tt> operations.
 49.1199 +     *
 49.1200 +     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
 49.1201 +     * that will never throw {@link ConcurrentModificationException},
 49.1202 +     * and guarantees to traverse elements as they existed upon
 49.1203 +     * construction of the iterator, and may (but is not guaranteed to)
 49.1204 +     * reflect any modifications subsequent to construction.
 49.1205 +     */
 49.1206 +    public Collection<V> values() {
 49.1207 +        Collection<V> vs = values;
 49.1208 +        return (vs != null) ? vs : (values = new Values());
 49.1209 +    }
 49.1210 +
 49.1211 +    /**
 49.1212 +     * Returns a {@link Set} view of the mappings contained in this map.
 49.1213 +     * The set is backed by the map, so changes to the map are
 49.1214 +     * reflected in the set, and vice-versa.  The set supports element
 49.1215 +     * removal, which removes the corresponding mapping from the map,
 49.1216 +     * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
 49.1217 +     * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
 49.1218 +     * operations.  It does not support the <tt>add</tt> or
 49.1219 +     * <tt>addAll</tt> operations.
 49.1220 +     *
 49.1221 +     * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
 49.1222 +     * that will never throw {@link ConcurrentModificationException},
 49.1223 +     * and guarantees to traverse elements as they existed upon
 49.1224 +     * construction of the iterator, and may (but is not guaranteed to)
 49.1225 +     * reflect any modifications subsequent to construction.
 49.1226 +     */
 49.1227 +    public Set<Map.Entry<K,V>> entrySet() {
 49.1228 +        Set<Map.Entry<K,V>> es = entrySet;
 49.1229 +        return (es != null) ? es : (entrySet = new EntrySet());
 49.1230 +    }
 49.1231 +
 49.1232 +    /**
 49.1233 +     * Returns an enumeration of the keys in this table.
 49.1234 +     *
 49.1235 +     * @return an enumeration of the keys in this table
 49.1236 +     * @see #keySet()
 49.1237 +     */
 49.1238 +    public Enumeration<K> keys() {
 49.1239 +        return new KeyIterator();
 49.1240 +    }
 49.1241 +
 49.1242 +    /**
 49.1243 +     * Returns an enumeration of the values in this table.
 49.1244 +     *
 49.1245 +     * @return an enumeration of the values in this table
 49.1246 +     * @see #values()
 49.1247 +     */
 49.1248 +    public Enumeration<V> elements() {
 49.1249 +        return new ValueIterator();
 49.1250 +    }
 49.1251 +
 49.1252 +    /* ---------------- Iterator Support -------------- */
 49.1253 +
 49.1254 +    abstract class HashIterator {
 49.1255 +        int nextSegmentIndex;
 49.1256 +        int nextTableIndex;
 49.1257 +        HashEntry<K,V>[] currentTable;
 49.1258 +        HashEntry<K, V> nextEntry;
 49.1259 +        HashEntry<K, V> lastReturned;
 49.1260 +
 49.1261 +        HashIterator() {
 49.1262 +            nextSegmentIndex = segments.length - 1;
 49.1263 +            nextTableIndex = -1;
 49.1264 +            advance();
 49.1265 +        }
 49.1266 +
 49.1267 +        /**
 49.1268 +         * Set nextEntry to first node of next non-empty table
 49.1269 +         * (in backwards order, to simplify checks).
 49.1270 +         */
 49.1271 +        final void advance() {
 49.1272 +            for (;;) {
 49.1273 +                if (nextTableIndex >= 0) {
 49.1274 +                    if ((nextEntry = entryAt(currentTable,
 49.1275 +                                             nextTableIndex--)) != null)
 49.1276 +                        break;
 49.1277 +                }
 49.1278 +                else if (nextSegmentIndex >= 0) {
 49.1279 +                    Segment<K,V> seg = segmentAt(segments, nextSegmentIndex--);
 49.1280 +                    if (seg != null && (currentTable = seg.table) != null)
 49.1281 +                        nextTableIndex = currentTable.length - 1;
 49.1282 +                }
 49.1283 +                else
 49.1284 +                    break;
 49.1285 +            }
 49.1286 +        }
 49.1287 +
 49.1288 +        final HashEntry<K,V> nextEntry() {
 49.1289 +            HashEntry<K,V> e = nextEntry;
 49.1290 +            if (e == null)
 49.1291 +                throw new NoSuchElementException();
 49.1292 +            lastReturned = e; // cannot assign until after null check
 49.1293 +            if ((nextEntry = e.next) == null)
 49.1294 +                advance();
 49.1295 +            return e;
 49.1296 +        }
 49.1297 +
 49.1298 +        public final boolean hasNext() { return nextEntry != null; }
 49.1299 +        public final boolean hasMoreElements() { return nextEntry != null; }
 49.1300 +
 49.1301 +        public final void remove() {
 49.1302 +            if (lastReturned == null)
 49.1303 +                throw new IllegalStateException();
 49.1304 +            ConcurrentHashMap.this.remove(lastReturned.key);
 49.1305 +            lastReturned = null;
 49.1306 +        }
 49.1307 +    }
 49.1308 +
 49.1309 +    final class KeyIterator
 49.1310 +        extends HashIterator
 49.1311 +        implements Iterator<K>, Enumeration<K>
 49.1312 +    {
 49.1313 +        public final K next()        { return super.nextEntry().key; }
 49.1314 +        public final K nextElement() { return super.nextEntry().key; }
 49.1315 +    }
 49.1316 +
 49.1317 +    final class ValueIterator
 49.1318 +        extends HashIterator
 49.1319 +        implements Iterator<V>, Enumeration<V>
 49.1320 +    {
 49.1321 +        public final V next()        { return super.nextEntry().value; }
 49.1322 +        public final V nextElement() { return super.nextEntry().value; }
 49.1323 +    }
 49.1324 +
 49.1325 +    /**
 49.1326 +     * Custom Entry class used by EntryIterator.next(), that relays
 49.1327 +     * setValue changes to the underlying map.
 49.1328 +     */
 49.1329 +    final class WriteThroughEntry
 49.1330 +        extends AbstractMap.SimpleEntry<K,V>
 49.1331 +    {
 49.1332 +        WriteThroughEntry(K k, V v) {
 49.1333 +            super(k,v);
 49.1334 +        }
 49.1335 +
 49.1336 +        /**
 49.1337 +         * Set our entry's value and write through to the map. The
 49.1338 +         * value to return is somewhat arbitrary here. Since a
 49.1339 +         * WriteThroughEntry does not necessarily track asynchronous
 49.1340 +         * changes, the most recent "previous" value could be
 49.1341 +         * different from what we return (or could even have been
 49.1342 +         * removed in which case the put will re-establish). We do not
 49.1343 +         * and cannot guarantee more.
 49.1344 +         */
 49.1345 +        public V setValue(V value) {
 49.1346 +            if (value == null) throw new NullPointerException();
 49.1347 +            V v = super.setValue(value);
 49.1348 +            ConcurrentHashMap.this.put(getKey(), value);
 49.1349 +            return v;
 49.1350 +        }
 49.1351 +    }
 49.1352 +
 49.1353 +    final class EntryIterator
 49.1354 +        extends HashIterator
 49.1355 +        implements Iterator<Entry<K,V>>
 49.1356 +    {
 49.1357 +        public Map.Entry<K,V> next() {
 49.1358 +            HashEntry<K,V> e = super.nextEntry();
 49.1359 +            return new WriteThroughEntry(e.key, e.value);
 49.1360 +        }
 49.1361 +    }
 49.1362 +
 49.1363 +    final class KeySet extends AbstractSet<K> {
 49.1364 +        public Iterator<K> iterator() {
 49.1365 +            return new KeyIterator();
 49.1366 +        }
 49.1367 +        public int size() {
 49.1368 +            return ConcurrentHashMap.this.size();
 49.1369 +        }
 49.1370 +        public boolean isEmpty() {
 49.1371 +            return ConcurrentHashMap.this.isEmpty();
 49.1372 +        }
 49.1373 +        public boolean contains(Object o) {
 49.1374 +            return ConcurrentHashMap.this.containsKey(o);
 49.1375 +        }
 49.1376 +        public boolean remove(Object o) {
 49.1377 +            return ConcurrentHashMap.this.remove(o) != null;
 49.1378 +        }
 49.1379 +        public void clear() {
 49.1380 +            ConcurrentHashMap.this.clear();
 49.1381 +        }
 49.1382 +    }
 49.1383 +
 49.1384 +    final class Values extends AbstractCollection<V> {
 49.1385 +        public Iterator<V> iterator() {
 49.1386 +            return new ValueIterator();
 49.1387 +        }
 49.1388 +        public int size() {
 49.1389 +            return ConcurrentHashMap.this.size();
 49.1390 +        }
 49.1391 +        public boolean isEmpty() {
 49.1392 +            return ConcurrentHashMap.this.isEmpty();
 49.1393 +        }
 49.1394 +        public boolean contains(Object o) {
 49.1395 +            return ConcurrentHashMap.this.containsValue(o);
 49.1396 +        }
 49.1397 +        public void clear() {
 49.1398 +            ConcurrentHashMap.this.clear();
 49.1399 +        }
 49.1400 +    }
 49.1401 +
 49.1402 +    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
 49.1403 +        public Iterator<Map.Entry<K,V>> iterator() {
 49.1404 +            return new EntryIterator();
 49.1405 +        }
 49.1406 +        public boolean contains(Object o) {
 49.1407 +            if (!(o instanceof Map.Entry))
 49.1408 +                return false;
 49.1409 +            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
 49.1410 +            V v = ConcurrentHashMap.this.get(e.getKey());
 49.1411 +            return v != null && v.equals(e.getValue());
 49.1412 +        }
 49.1413 +        public boolean remove(Object o) {
 49.1414 +            if (!(o instanceof Map.Entry))
 49.1415 +                return false;
 49.1416 +            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
 49.1417 +            return ConcurrentHashMap.this.remove(e.getKey(), e.getValue());
 49.1418 +        }
 49.1419 +        public int size() {
 49.1420 +            return ConcurrentHashMap.this.size();
 49.1421 +        }
 49.1422 +        public boolean isEmpty() {
 49.1423 +            return ConcurrentHashMap.this.isEmpty();
 49.1424 +        }
 49.1425 +        public void clear() {
 49.1426 +            ConcurrentHashMap.this.clear();
 49.1427 +        }
 49.1428 +    }
 49.1429 +
 49.1430 +    /* ---------------- Serialization Support -------------- */
 49.1431 +
 49.1432 +    /**
 49.1433 +     * Save the state of the <tt>ConcurrentHashMap</tt> instance to a
 49.1434 +     * stream (i.e., serialize it).
 49.1435 +     * @param s the stream
 49.1436 +     * @serialData
 49.1437 +     * the key (Object) and value (Object)
 49.1438 +     * for each key-value mapping, followed by a null pair.
 49.1439 +     * The key-value mappings are emitted in no particular order.
 49.1440 +     */
 49.1441 +    private void writeObject(java.io.ObjectOutputStream s) throws IOException {
 49.1442 +        // force all segments for serialization compatibility
 49.1443 +        for (int k = 0; k < segments.length; ++k)
 49.1444 +            ensureSegment(k);
 49.1445 +        s.defaultWriteObject();
 49.1446 +
 49.1447 +        final Segment<K,V>[] segments = this.segments;
 49.1448 +        for (int k = 0; k < segments.length; ++k) {
 49.1449 +            Segment<K,V> seg = segmentAt(segments, k);
 49.1450 +            seg.lock();
 49.1451 +            try {
 49.1452 +                HashEntry<K,V>[] tab = seg.table;
 49.1453 +                for (int i = 0; i < tab.length; ++i) {
 49.1454 +                    HashEntry<K,V> e;
 49.1455 +                    for (e = entryAt(tab, i); e != null; e = e.next) {
 49.1456 +                        s.writeObject(e.key);
 49.1457 +                        s.writeObject(e.value);
 49.1458 +                    }
 49.1459 +                }
 49.1460 +            } finally {
 49.1461 +                seg.unlock();
 49.1462 +            }
 49.1463 +        }
 49.1464 +        s.writeObject(null);
 49.1465 +        s.writeObject(null);
 49.1466 +    }
 49.1467 +
 49.1468 +    /**
 49.1469 +     * Reconstitute the <tt>ConcurrentHashMap</tt> instance from a
 49.1470 +     * stream (i.e., deserialize it).
 49.1471 +     * @param s the stream
 49.1472 +     */
 49.1473 +    @SuppressWarnings("unchecked")
 49.1474 +    private void readObject(java.io.ObjectInputStream s)
 49.1475 +        throws IOException, ClassNotFoundException {
 49.1476 +        s.defaultReadObject();
 49.1477 +
 49.1478 +        // Re-initialize segments to be minimally sized, and let grow.
 49.1479 +        int cap = MIN_SEGMENT_TABLE_CAPACITY;
 49.1480 +        final Segment<K,V>[] segments = this.segments;
 49.1481 +        for (int k = 0; k < segments.length; ++k) {
 49.1482 +            Segment<K,V> seg = segments[k];
 49.1483 +            if (seg != null) {
 49.1484 +                seg.threshold = (int)(cap * seg.loadFactor);
 49.1485 +                seg.table = (HashEntry<K,V>[]) new HashEntry[cap];
 49.1486 +            }
 49.1487 +        }
 49.1488 +
 49.1489 +        // Read the keys and values, and put the mappings in the table
 49.1490 +        for (;;) {
 49.1491 +            K key = (K) s.readObject();
 49.1492 +            V value = (V) s.readObject();
 49.1493 +            if (key == null)
 49.1494 +                break;
 49.1495 +            put(key, value);
 49.1496 +        }
 49.1497 +    }
 49.1498 +
 49.1499 +    // Unsafe mechanics
 49.1500 +    private static final sun.misc.Unsafe UNSAFE;
 49.1501 +    private static final long SBASE;
 49.1502 +    private static final int SSHIFT;
 49.1503 +    private static final long TBASE;
 49.1504 +    private static final int TSHIFT;
 49.1505 +
 49.1506 +    static {
 49.1507 +        int ss, ts;
 49.1508 +        try {
 49.1509 +            UNSAFE = sun.misc.Unsafe.getUnsafe();
 49.1510 +            Class tc = HashEntry[].class;
 49.1511 +            Class sc = Segment[].class;
 49.1512 +            TBASE = UNSAFE.arrayBaseOffset(tc);
 49.1513 +            SBASE = UNSAFE.arrayBaseOffset(sc);
 49.1514 +            ts = UNSAFE.arrayIndexScale(tc);
 49.1515 +            ss = UNSAFE.arrayIndexScale(sc);
 49.1516 +        } catch (Exception e) {
 49.1517 +            throw new Error(e);
 49.1518 +        }
 49.1519 +        if ((ss & (ss-1)) != 0 || (ts & (ts-1)) != 0)
 49.1520 +            throw new Error("data type scale not a power of two");
 49.1521 +        SSHIFT = 31 - Integer.numberOfLeadingZeros(ss);
 49.1522 +        TSHIFT = 31 - Integer.numberOfLeadingZeros(ts);
 49.1523 +    }
 49.1524 +
 49.1525 +}
    50.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    50.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/ConcurrentMap.java	Thu Oct 03 15:40:35 2013 +0200
    50.3 @@ -0,0 +1,165 @@
    50.4 +/*
    50.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    50.6 + *
    50.7 + * This code is free software; you can redistribute it and/or modify it
    50.8 + * under the terms of the GNU General Public License version 2 only, as
    50.9 + * published by the Free Software Foundation.  Oracle designates this
   50.10 + * particular file as subject to the "Classpath" exception as provided
   50.11 + * by Oracle in the LICENSE file that accompanied this code.
   50.12 + *
   50.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   50.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   50.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   50.16 + * version 2 for more details (a copy is included in the LICENSE file that
   50.17 + * accompanied this code).
   50.18 + *
   50.19 + * You should have received a copy of the GNU General Public License version
   50.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   50.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   50.22 + *
   50.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   50.24 + * or visit www.oracle.com if you need additional information or have any
   50.25 + * questions.
   50.26 + */
   50.27 +
   50.28 +/*
   50.29 + * This file is available under and governed by the GNU General Public
   50.30 + * License version 2 only, as published by the Free Software Foundation.
   50.31 + * However, the following notice accompanied the original version of this
   50.32 + * file:
   50.33 + *
   50.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   50.35 + * Expert Group and released to the public domain, as explained at
   50.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   50.37 + */
   50.38 +
   50.39 +package java.util.concurrent;
   50.40 +import java.util.Map;
   50.41 +
   50.42 +/**
   50.43 + * A {@link java.util.Map} providing additional atomic
   50.44 + * <tt>putIfAbsent</tt>, <tt>remove</tt>, and <tt>replace</tt> methods.
   50.45 + *
   50.46 + * <p>Memory consistency effects: As with other concurrent
   50.47 + * collections, actions in a thread prior to placing an object into a
   50.48 + * {@code ConcurrentMap} as a key or value
   50.49 + * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
   50.50 + * actions subsequent to the access or removal of that object from
   50.51 + * the {@code ConcurrentMap} in another thread.
   50.52 + *
   50.53 + * <p>This interface is a member of the
   50.54 + * <a href="{@docRoot}/../technotes/guides/collections/index.html">
   50.55 + * Java Collections Framework</a>.
   50.56 + *
   50.57 + * @since 1.5
   50.58 + * @author Doug Lea
   50.59 + * @param <K> the type of keys maintained by this map
   50.60 + * @param <V> the type of mapped values
   50.61 + */
   50.62 +public interface ConcurrentMap<K, V> extends Map<K, V> {
   50.63 +    /**
   50.64 +     * If the specified key is not already associated
   50.65 +     * with a value, associate it with the given value.
   50.66 +     * This is equivalent to
   50.67 +     * <pre>
   50.68 +     *   if (!map.containsKey(key))
   50.69 +     *       return map.put(key, value);
   50.70 +     *   else
   50.71 +     *       return map.get(key);</pre>
   50.72 +     * except that the action is performed atomically.
   50.73 +     *
   50.74 +     * @param key key with which the specified value is to be associated
   50.75 +     * @param value value to be associated with the specified key
   50.76 +     * @return the previous value associated with the specified key, or
   50.77 +     *         <tt>null</tt> if there was no mapping for the key.
   50.78 +     *         (A <tt>null</tt> return can also indicate that the map
   50.79 +     *         previously associated <tt>null</tt> with the key,
   50.80 +     *         if the implementation supports null values.)
   50.81 +     * @throws UnsupportedOperationException if the <tt>put</tt> operation
   50.82 +     *         is not supported by this map
   50.83 +     * @throws ClassCastException if the class of the specified key or value
   50.84 +     *         prevents it from being stored in this map
   50.85 +     * @throws NullPointerException if the specified key or value is null,
   50.86 +     *         and this map does not permit null keys or values
   50.87 +     * @throws IllegalArgumentException if some property of the specified key
   50.88 +     *         or value prevents it from being stored in this map
   50.89 +     *
   50.90 +     */
   50.91 +    V putIfAbsent(K key, V value);
   50.92 +
   50.93 +    /**
   50.94 +     * Removes the entry for a key only if currently mapped to a given value.
   50.95 +     * This is equivalent to
   50.96 +     * <pre>
   50.97 +     *   if (map.containsKey(key) &amp;&amp; map.get(key).equals(value)) {
   50.98 +     *       map.remove(key);
   50.99 +     *       return true;
  50.100 +     *   } else return false;</pre>
  50.101 +     * except that the action is performed atomically.
  50.102 +     *
  50.103 +     * @param key key with which the specified value is associated
  50.104 +     * @param value value expected to be associated with the specified key
  50.105 +     * @return <tt>true</tt> if the value was removed
  50.106 +     * @throws UnsupportedOperationException if the <tt>remove</tt> operation
  50.107 +     *         is not supported by this map
  50.108 +     * @throws ClassCastException if the key or value is of an inappropriate
  50.109 +     *         type for this map
  50.110 +     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
  50.111 +     * @throws NullPointerException if the specified key or value is null,
  50.112 +     *         and this map does not permit null keys or values
  50.113 +     *         (<a href="../Collection.html#optional-restrictions">optional</a>)
  50.114 +     */
  50.115 +    boolean remove(Object key, Object value);
  50.116 +
  50.117 +    /**
  50.118 +     * Replaces the entry for a key only if currently mapped to a given value.
  50.119 +     * This is equivalent to
  50.120 +     * <pre>
  50.121 +     *   if (map.containsKey(key) &amp;&amp; map.get(key).equals(oldValue)) {
  50.122 +     *       map.put(key, newValue);
  50.123 +     *       return true;
  50.124 +     *   } else return false;</pre>
  50.125 +     * except that the action is performed atomically.
  50.126 +     *
  50.127 +     * @param key key with which the specified value is associated
  50.128 +     * @param oldValue value expected to be associated with the specified key
  50.129 +     * @param newValue value to be associated with the specified key
  50.130 +     * @return <tt>true</tt> if the value was replaced
  50.131 +     * @throws UnsupportedOperationException if the <tt>put</tt> operation
  50.132 +     *         is not supported by this map
  50.133 +     * @throws ClassCastException if the class of a specified key or value
  50.134 +     *         prevents it from being stored in this map
  50.135 +     * @throws NullPointerException if a specified key or value is null,
  50.136 +     *         and this map does not permit null keys or values
  50.137 +     * @throws IllegalArgumentException if some property of a specified key
  50.138 +     *         or value prevents it from being stored in this map
  50.139 +     */
  50.140 +    boolean replace(K key, V oldValue, V newValue);
  50.141 +
  50.142 +    /**
  50.143 +     * Replaces the entry for a key only if currently mapped to some value.
  50.144 +     * This is equivalent to
  50.145 +     * <pre>
  50.146 +     *   if (map.containsKey(key)) {
  50.147 +     *       return map.put(key, value);
  50.148 +     *   } else return null;</pre>
  50.149 +     * except that the action is performed atomically.
  50.150 +     *
  50.151 +     * @param key key with which the specified value is associated
  50.152 +     * @param value value to be associated with the specified key
  50.153 +     * @return the previous value associated with the specified key, or
  50.154 +     *         <tt>null</tt> if there was no mapping for the key.
  50.155 +     *         (A <tt>null</tt> return can also indicate that the map
  50.156 +     *         previously associated <tt>null</tt> with the key,
  50.157 +     *         if the implementation supports null values.)
  50.158 +     * @throws UnsupportedOperationException if the <tt>put</tt> operation
  50.159 +     *         is not supported by this map
  50.160 +     * @throws ClassCastException if the class of the specified key or value
  50.161 +     *         prevents it from being stored in this map
  50.162 +     * @throws NullPointerException if the specified key or value is null,
  50.163 +     *         and this map does not permit null keys or values
  50.164 +     * @throws IllegalArgumentException if some property of the specified key
  50.165 +     *         or value prevents it from being stored in this map
  50.166 +     */
  50.167 +    V replace(K key, V value);
  50.168 +}
    51.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    51.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicBoolean.java	Thu Oct 03 15:40:35 2013 +0200
    51.3 @@ -0,0 +1,164 @@
    51.4 +/*
    51.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    51.6 + *
    51.7 + * This code is free software; you can redistribute it and/or modify it
    51.8 + * under the terms of the GNU General Public License version 2 only, as
    51.9 + * published by the Free Software Foundation.  Oracle designates this
   51.10 + * particular file as subject to the "Classpath" exception as provided
   51.11 + * by Oracle in the LICENSE file that accompanied this code.
   51.12 + *
   51.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   51.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   51.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   51.16 + * version 2 for more details (a copy is included in the LICENSE file that
   51.17 + * accompanied this code).
   51.18 + *
   51.19 + * You should have received a copy of the GNU General Public License version
   51.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   51.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   51.22 + *
   51.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   51.24 + * or visit www.oracle.com if you need additional information or have any
   51.25 + * questions.
   51.26 + */
   51.27 +
   51.28 +/*
   51.29 + * This file is available under and governed by the GNU General Public
   51.30 + * License version 2 only, as published by the Free Software Foundation.
   51.31 + * However, the following notice accompanied the original version of this
   51.32 + * file:
   51.33 + *
   51.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   51.35 + * Expert Group and released to the public domain, as explained at
   51.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   51.37 + */
   51.38 +
   51.39 +package java.util.concurrent.atomic;
   51.40 +import sun.misc.Unsafe;
   51.41 +
   51.42 +/**
   51.43 + * A {@code boolean} value that may be updated atomically. See the
   51.44 + * {@link java.util.concurrent.atomic} package specification for
   51.45 + * description of the properties of atomic variables. An
   51.46 + * {@code AtomicBoolean} is used in applications such as atomically
   51.47 + * updated flags, and cannot be used as a replacement for a
   51.48 + * {@link java.lang.Boolean}.
   51.49 + *
   51.50 + * @since 1.5
   51.51 + * @author Doug Lea
   51.52 + */
   51.53 +public class AtomicBoolean implements java.io.Serializable {
   51.54 +    private static final long serialVersionUID = 4654671469794556979L;
   51.55 +    // setup to use Unsafe.compareAndSwapInt for updates
   51.56 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   51.57 +    private static final long valueOffset;
   51.58 +
   51.59 +    static {
   51.60 +      try {
   51.61 +        valueOffset = unsafe.objectFieldOffset
   51.62 +            (AtomicBoolean.class.getDeclaredField("value"));
   51.63 +      } catch (Exception ex) { throw new Error(ex); }
   51.64 +    }
   51.65 +
   51.66 +    private volatile int value;
   51.67 +
   51.68 +    /**
   51.69 +     * Creates a new {@code AtomicBoolean} with the given initial value.
   51.70 +     *
   51.71 +     * @param initialValue the initial value
   51.72 +     */
   51.73 +    public AtomicBoolean(boolean initialValue) {
   51.74 +        value = initialValue ? 1 : 0;
   51.75 +    }
   51.76 +
   51.77 +    /**
   51.78 +     * Creates a new {@code AtomicBoolean} with initial value {@code false}.
   51.79 +     */
   51.80 +    public AtomicBoolean() {
   51.81 +    }
   51.82 +
   51.83 +    /**
   51.84 +     * Returns the current value.
   51.85 +     *
   51.86 +     * @return the current value
   51.87 +     */
   51.88 +    public final boolean get() {
   51.89 +        return value != 0;
   51.90 +    }
   51.91 +
   51.92 +    /**
   51.93 +     * Atomically sets the value to the given updated value
   51.94 +     * if the current value {@code ==} the expected value.
   51.95 +     *
   51.96 +     * @param expect the expected value
   51.97 +     * @param update the new value
   51.98 +     * @return true if successful. False return indicates that
   51.99 +     * the actual value was not equal to the expected value.
  51.100 +     */
  51.101 +    public final boolean compareAndSet(boolean expect, boolean update) {
  51.102 +        int e = expect ? 1 : 0;
  51.103 +        int u = update ? 1 : 0;
  51.104 +        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
  51.105 +    }
  51.106 +
  51.107 +    /**
  51.108 +     * Atomically sets the value to the given updated value
  51.109 +     * if the current value {@code ==} the expected value.
  51.110 +     *
  51.111 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  51.112 +     * and does not provide ordering guarantees, so is only rarely an
  51.113 +     * appropriate alternative to {@code compareAndSet}.
  51.114 +     *
  51.115 +     * @param expect the expected value
  51.116 +     * @param update the new value
  51.117 +     * @return true if successful.
  51.118 +     */
  51.119 +    public boolean weakCompareAndSet(boolean expect, boolean update) {
  51.120 +        int e = expect ? 1 : 0;
  51.121 +        int u = update ? 1 : 0;
  51.122 +        return unsafe.compareAndSwapInt(this, valueOffset, e, u);
  51.123 +    }
  51.124 +
  51.125 +    /**
  51.126 +     * Unconditionally sets to the given value.
  51.127 +     *
  51.128 +     * @param newValue the new value
  51.129 +     */
  51.130 +    public final void set(boolean newValue) {
  51.131 +        value = newValue ? 1 : 0;
  51.132 +    }
  51.133 +
  51.134 +    /**
  51.135 +     * Eventually sets to the given value.
  51.136 +     *
  51.137 +     * @param newValue the new value
  51.138 +     * @since 1.6
  51.139 +     */
  51.140 +    public final void lazySet(boolean newValue) {
  51.141 +        int v = newValue ? 1 : 0;
  51.142 +        unsafe.putOrderedInt(this, valueOffset, v);
  51.143 +    }
  51.144 +
  51.145 +    /**
  51.146 +     * Atomically sets to the given value and returns the previous value.
  51.147 +     *
  51.148 +     * @param newValue the new value
  51.149 +     * @return the previous value
  51.150 +     */
  51.151 +    public final boolean getAndSet(boolean newValue) {
  51.152 +        for (;;) {
  51.153 +            boolean current = get();
  51.154 +            if (compareAndSet(current, newValue))
  51.155 +                return current;
  51.156 +        }
  51.157 +    }
  51.158 +
  51.159 +    /**
  51.160 +     * Returns the String representation of the current value.
  51.161 +     * @return the String representation of the current value.
  51.162 +     */
  51.163 +    public String toString() {
  51.164 +        return Boolean.toString(get());
  51.165 +    }
  51.166 +
  51.167 +}
    52.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    52.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicInteger.java	Thu Oct 03 15:40:35 2013 +0200
    52.3 @@ -0,0 +1,265 @@
    52.4 +/*
    52.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    52.6 + *
    52.7 + * This code is free software; you can redistribute it and/or modify it
    52.8 + * under the terms of the GNU General Public License version 2 only, as
    52.9 + * published by the Free Software Foundation.  Oracle designates this
   52.10 + * particular file as subject to the "Classpath" exception as provided
   52.11 + * by Oracle in the LICENSE file that accompanied this code.
   52.12 + *
   52.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   52.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   52.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   52.16 + * version 2 for more details (a copy is included in the LICENSE file that
   52.17 + * accompanied this code).
   52.18 + *
   52.19 + * You should have received a copy of the GNU General Public License version
   52.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   52.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   52.22 + *
   52.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   52.24 + * or visit www.oracle.com if you need additional information or have any
   52.25 + * questions.
   52.26 + */
   52.27 +
   52.28 +/*
   52.29 + * This file is available under and governed by the GNU General Public
   52.30 + * License version 2 only, as published by the Free Software Foundation.
   52.31 + * However, the following notice accompanied the original version of this
   52.32 + * file:
   52.33 + *
   52.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   52.35 + * Expert Group and released to the public domain, as explained at
   52.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   52.37 + */
   52.38 +
   52.39 +package java.util.concurrent.atomic;
   52.40 +import sun.misc.Unsafe;
   52.41 +
   52.42 +/**
   52.43 + * An {@code int} value that may be updated atomically.  See the
   52.44 + * {@link java.util.concurrent.atomic} package specification for
   52.45 + * description of the properties of atomic variables. An
   52.46 + * {@code AtomicInteger} is used in applications such as atomically
   52.47 + * incremented counters, and cannot be used as a replacement for an
   52.48 + * {@link java.lang.Integer}. However, this class does extend
   52.49 + * {@code Number} to allow uniform access by tools and utilities that
   52.50 + * deal with numerically-based classes.
   52.51 + *
   52.52 + * @since 1.5
   52.53 + * @author Doug Lea
   52.54 +*/
   52.55 +public class AtomicInteger extends Number implements java.io.Serializable {
   52.56 +    private static final long serialVersionUID = 6214790243416807050L;
   52.57 +
   52.58 +    // setup to use Unsafe.compareAndSwapInt for updates
   52.59 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   52.60 +    private static final long valueOffset;
   52.61 +
   52.62 +    static {
   52.63 +      try {
   52.64 +        valueOffset = unsafe.objectFieldOffset
   52.65 +            (AtomicInteger.class.getDeclaredField("value"));
   52.66 +      } catch (Exception ex) { throw new Error(ex); }
   52.67 +    }
   52.68 +
   52.69 +    private volatile int value;
   52.70 +
   52.71 +    /**
   52.72 +     * Creates a new AtomicInteger with the given initial value.
   52.73 +     *
   52.74 +     * @param initialValue the initial value
   52.75 +     */
   52.76 +    public AtomicInteger(int initialValue) {
   52.77 +        value = initialValue;
   52.78 +    }
   52.79 +
   52.80 +    /**
   52.81 +     * Creates a new AtomicInteger with initial value {@code 0}.
   52.82 +     */
   52.83 +    public AtomicInteger() {
   52.84 +    }
   52.85 +
   52.86 +    /**
   52.87 +     * Gets the current value.
   52.88 +     *
   52.89 +     * @return the current value
   52.90 +     */
   52.91 +    public final int get() {
   52.92 +        return value;
   52.93 +    }
   52.94 +
   52.95 +    /**
   52.96 +     * Sets to the given value.
   52.97 +     *
   52.98 +     * @param newValue the new value
   52.99 +     */
  52.100 +    public final void set(int newValue) {
  52.101 +        value = newValue;
  52.102 +    }
  52.103 +
  52.104 +    /**
  52.105 +     * Eventually sets to the given value.
  52.106 +     *
  52.107 +     * @param newValue the new value
  52.108 +     * @since 1.6
  52.109 +     */
  52.110 +    public final void lazySet(int newValue) {
  52.111 +        unsafe.putOrderedInt(this, valueOffset, newValue);
  52.112 +    }
  52.113 +
  52.114 +    /**
  52.115 +     * Atomically sets to the given value and returns the old value.
  52.116 +     *
  52.117 +     * @param newValue the new value
  52.118 +     * @return the previous value
  52.119 +     */
  52.120 +    public final int getAndSet(int newValue) {
  52.121 +        for (;;) {
  52.122 +            int current = get();
  52.123 +            if (compareAndSet(current, newValue))
  52.124 +                return current;
  52.125 +        }
  52.126 +    }
  52.127 +
  52.128 +    /**
  52.129 +     * Atomically sets the value to the given updated value
  52.130 +     * if the current value {@code ==} the expected value.
  52.131 +     *
  52.132 +     * @param expect the expected value
  52.133 +     * @param update the new value
  52.134 +     * @return true if successful. False return indicates that
  52.135 +     * the actual value was not equal to the expected value.
  52.136 +     */
  52.137 +    public final boolean compareAndSet(int expect, int update) {
  52.138 +        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
  52.139 +    }
  52.140 +
  52.141 +    /**
  52.142 +     * Atomically sets the value to the given updated value
  52.143 +     * if the current value {@code ==} the expected value.
  52.144 +     *
  52.145 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  52.146 +     * and does not provide ordering guarantees, so is only rarely an
  52.147 +     * appropriate alternative to {@code compareAndSet}.
  52.148 +     *
  52.149 +     * @param expect the expected value
  52.150 +     * @param update the new value
  52.151 +     * @return true if successful.
  52.152 +     */
  52.153 +    public final boolean weakCompareAndSet(int expect, int update) {
  52.154 +        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
  52.155 +    }
  52.156 +
  52.157 +    /**
  52.158 +     * Atomically increments by one the current value.
  52.159 +     *
  52.160 +     * @return the previous value
  52.161 +     */
  52.162 +    public final int getAndIncrement() {
  52.163 +        for (;;) {
  52.164 +            int current = get();
  52.165 +            int next = current + 1;
  52.166 +            if (compareAndSet(current, next))
  52.167 +                return current;
  52.168 +        }
  52.169 +    }
  52.170 +
  52.171 +    /**
  52.172 +     * Atomically decrements by one the current value.
  52.173 +     *
  52.174 +     * @return the previous value
  52.175 +     */
  52.176 +    public final int getAndDecrement() {
  52.177 +        for (;;) {
  52.178 +            int current = get();
  52.179 +            int next = current - 1;
  52.180 +            if (compareAndSet(current, next))
  52.181 +                return current;
  52.182 +        }
  52.183 +    }
  52.184 +
  52.185 +    /**
  52.186 +     * Atomically adds the given value to the current value.
  52.187 +     *
  52.188 +     * @param delta the value to add
  52.189 +     * @return the previous value
  52.190 +     */
  52.191 +    public final int getAndAdd(int delta) {
  52.192 +        for (;;) {
  52.193 +            int current = get();
  52.194 +            int next = current + delta;
  52.195 +            if (compareAndSet(current, next))
  52.196 +                return current;
  52.197 +        }
  52.198 +    }
  52.199 +
  52.200 +    /**
  52.201 +     * Atomically increments by one the current value.
  52.202 +     *
  52.203 +     * @return the updated value
  52.204 +     */
  52.205 +    public final int incrementAndGet() {
  52.206 +        for (;;) {
  52.207 +            int current = get();
  52.208 +            int next = current + 1;
  52.209 +            if (compareAndSet(current, next))
  52.210 +                return next;
  52.211 +        }
  52.212 +    }
  52.213 +
  52.214 +    /**
  52.215 +     * Atomically decrements by one the current value.
  52.216 +     *
  52.217 +     * @return the updated value
  52.218 +     */
  52.219 +    public final int decrementAndGet() {
  52.220 +        for (;;) {
  52.221 +            int current = get();
  52.222 +            int next = current - 1;
  52.223 +            if (compareAndSet(current, next))
  52.224 +                return next;
  52.225 +        }
  52.226 +    }
  52.227 +
  52.228 +    /**
  52.229 +     * Atomically adds the given value to the current value.
  52.230 +     *
  52.231 +     * @param delta the value to add
  52.232 +     * @return the updated value
  52.233 +     */
  52.234 +    public final int addAndGet(int delta) {
  52.235 +        for (;;) {
  52.236 +            int current = get();
  52.237 +            int next = current + delta;
  52.238 +            if (compareAndSet(current, next))
  52.239 +                return next;
  52.240 +        }
  52.241 +    }
  52.242 +
  52.243 +    /**
  52.244 +     * Returns the String representation of the current value.
  52.245 +     * @return the String representation of the current value.
  52.246 +     */
  52.247 +    public String toString() {
  52.248 +        return Integer.toString(get());
  52.249 +    }
  52.250 +
  52.251 +
  52.252 +    public int intValue() {
  52.253 +        return get();
  52.254 +    }
  52.255 +
  52.256 +    public long longValue() {
  52.257 +        return (long)get();
  52.258 +    }
  52.259 +
  52.260 +    public float floatValue() {
  52.261 +        return (float)get();
  52.262 +    }
  52.263 +
  52.264 +    public double doubleValue() {
  52.265 +        return (double)get();
  52.266 +    }
  52.267 +
  52.268 +}
    53.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    53.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicIntegerArray.java	Thu Oct 03 15:40:35 2013 +0200
    53.3 @@ -0,0 +1,284 @@
    53.4 +/*
    53.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    53.6 + *
    53.7 + * This code is free software; you can redistribute it and/or modify it
    53.8 + * under the terms of the GNU General Public License version 2 only, as
    53.9 + * published by the Free Software Foundation.  Oracle designates this
   53.10 + * particular file as subject to the "Classpath" exception as provided
   53.11 + * by Oracle in the LICENSE file that accompanied this code.
   53.12 + *
   53.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   53.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   53.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   53.16 + * version 2 for more details (a copy is included in the LICENSE file that
   53.17 + * accompanied this code).
   53.18 + *
   53.19 + * You should have received a copy of the GNU General Public License version
   53.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   53.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   53.22 + *
   53.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   53.24 + * or visit www.oracle.com if you need additional information or have any
   53.25 + * questions.
   53.26 + */
   53.27 +
   53.28 +/*
   53.29 + * This file is available under and governed by the GNU General Public
   53.30 + * License version 2 only, as published by the Free Software Foundation.
   53.31 + * However, the following notice accompanied the original version of this
   53.32 + * file:
   53.33 + *
   53.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   53.35 + * Expert Group and released to the public domain, as explained at
   53.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   53.37 + */
   53.38 +
   53.39 +package java.util.concurrent.atomic;
   53.40 +import sun.misc.Unsafe;
   53.41 +import java.util.*;
   53.42 +
   53.43 +/**
   53.44 + * An {@code int} array in which elements may be updated atomically.
   53.45 + * See the {@link java.util.concurrent.atomic} package
   53.46 + * specification for description of the properties of atomic
   53.47 + * variables.
   53.48 + * @since 1.5
   53.49 + * @author Doug Lea
   53.50 + */
   53.51 +public class AtomicIntegerArray implements java.io.Serializable {
   53.52 +    private static final long serialVersionUID = 2862133569453604235L;
   53.53 +
   53.54 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   53.55 +    private static final int base = unsafe.arrayBaseOffset(int[].class);
   53.56 +    private static final int shift;
   53.57 +    private final int[] array;
   53.58 +
   53.59 +    static {
   53.60 +        int scale = unsafe.arrayIndexScale(int[].class);
   53.61 +        if ((scale & (scale - 1)) != 0)
   53.62 +            throw new Error("data type scale not a power of two");
   53.63 +        shift = 31 - Integer.numberOfLeadingZeros(scale);
   53.64 +    }
   53.65 +
   53.66 +    private long checkedByteOffset(int i) {
   53.67 +        if (i < 0 || i >= array.length)
   53.68 +            throw new IndexOutOfBoundsException("index " + i);
   53.69 +
   53.70 +        return byteOffset(i);
   53.71 +    }
   53.72 +
   53.73 +    private static long byteOffset(int i) {
   53.74 +        return ((long) i << shift) + base;
   53.75 +    }
   53.76 +
   53.77 +    /**
   53.78 +     * Creates a new AtomicIntegerArray of the given length, with all
   53.79 +     * elements initially zero.
   53.80 +     *
   53.81 +     * @param length the length of the array
   53.82 +     */
   53.83 +    public AtomicIntegerArray(int length) {
   53.84 +        array = new int[length];
   53.85 +    }
   53.86 +
   53.87 +    /**
   53.88 +     * Creates a new AtomicIntegerArray with the same length as, and
   53.89 +     * all elements copied from, the given array.
   53.90 +     *
   53.91 +     * @param array the array to copy elements from
   53.92 +     * @throws NullPointerException if array is null
   53.93 +     */
   53.94 +    public AtomicIntegerArray(int[] array) {
   53.95 +        // Visibility guaranteed by final field guarantees
   53.96 +        this.array = array.clone();
   53.97 +    }
   53.98 +
   53.99 +    /**
  53.100 +     * Returns the length of the array.
  53.101 +     *
  53.102 +     * @return the length of the array
  53.103 +     */
  53.104 +    public final int length() {
  53.105 +        return array.length;
  53.106 +    }
  53.107 +
  53.108 +    /**
  53.109 +     * Gets the current value at position {@code i}.
  53.110 +     *
  53.111 +     * @param i the index
  53.112 +     * @return the current value
  53.113 +     */
  53.114 +    public final int get(int i) {
  53.115 +        return getRaw(checkedByteOffset(i));
  53.116 +    }
  53.117 +
  53.118 +    private int getRaw(long offset) {
  53.119 +        return unsafe.getIntVolatile(array, offset);
  53.120 +    }
  53.121 +
  53.122 +    /**
  53.123 +     * Sets the element at position {@code i} to the given value.
  53.124 +     *
  53.125 +     * @param i the index
  53.126 +     * @param newValue the new value
  53.127 +     */
  53.128 +    public final void set(int i, int newValue) {
  53.129 +        unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
  53.130 +    }
  53.131 +
  53.132 +    /**
  53.133 +     * Eventually sets the element at position {@code i} to the given value.
  53.134 +     *
  53.135 +     * @param i the index
  53.136 +     * @param newValue the new value
  53.137 +     * @since 1.6
  53.138 +     */
  53.139 +    public final void lazySet(int i, int newValue) {
  53.140 +        unsafe.putOrderedInt(array, checkedByteOffset(i), newValue);
  53.141 +    }
  53.142 +
  53.143 +    /**
  53.144 +     * Atomically sets the element at position {@code i} to the given
  53.145 +     * value and returns the old value.
  53.146 +     *
  53.147 +     * @param i the index
  53.148 +     * @param newValue the new value
  53.149 +     * @return the previous value
  53.150 +     */
  53.151 +    public final int getAndSet(int i, int newValue) {
  53.152 +        long offset = checkedByteOffset(i);
  53.153 +        while (true) {
  53.154 +            int current = getRaw(offset);
  53.155 +            if (compareAndSetRaw(offset, current, newValue))
  53.156 +                return current;
  53.157 +        }
  53.158 +    }
  53.159 +
  53.160 +    /**
  53.161 +     * Atomically sets the element at position {@code i} to the given
  53.162 +     * updated value if the current value {@code ==} the expected value.
  53.163 +     *
  53.164 +     * @param i the index
  53.165 +     * @param expect the expected value
  53.166 +     * @param update the new value
  53.167 +     * @return true if successful. False return indicates that
  53.168 +     * the actual value was not equal to the expected value.
  53.169 +     */
  53.170 +    public final boolean compareAndSet(int i, int expect, int update) {
  53.171 +        return compareAndSetRaw(checkedByteOffset(i), expect, update);
  53.172 +    }
  53.173 +
  53.174 +    private boolean compareAndSetRaw(long offset, int expect, int update) {
  53.175 +        return unsafe.compareAndSwapInt(array, offset, expect, update);
  53.176 +    }
  53.177 +
  53.178 +    /**
  53.179 +     * Atomically sets the element at position {@code i} to the given
  53.180 +     * updated value if the current value {@code ==} the expected value.
  53.181 +     *
  53.182 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  53.183 +     * and does not provide ordering guarantees, so is only rarely an
  53.184 +     * appropriate alternative to {@code compareAndSet}.
  53.185 +     *
  53.186 +     * @param i the index
  53.187 +     * @param expect the expected value
  53.188 +     * @param update the new value
  53.189 +     * @return true if successful.
  53.190 +     */
  53.191 +    public final boolean weakCompareAndSet(int i, int expect, int update) {
  53.192 +        return compareAndSet(i, expect, update);
  53.193 +    }
  53.194 +
  53.195 +    /**
  53.196 +     * Atomically increments by one the element at index {@code i}.
  53.197 +     *
  53.198 +     * @param i the index
  53.199 +     * @return the previous value
  53.200 +     */
  53.201 +    public final int getAndIncrement(int i) {
  53.202 +        return getAndAdd(i, 1);
  53.203 +    }
  53.204 +
  53.205 +    /**
  53.206 +     * Atomically decrements by one the element at index {@code i}.
  53.207 +     *
  53.208 +     * @param i the index
  53.209 +     * @return the previous value
  53.210 +     */
  53.211 +    public final int getAndDecrement(int i) {
  53.212 +        return getAndAdd(i, -1);
  53.213 +    }
  53.214 +
  53.215 +    /**
  53.216 +     * Atomically adds the given value to the element at index {@code i}.
  53.217 +     *
  53.218 +     * @param i the index
  53.219 +     * @param delta the value to add
  53.220 +     * @return the previous value
  53.221 +     */
  53.222 +    public final int getAndAdd(int i, int delta) {
  53.223 +        long offset = checkedByteOffset(i);
  53.224 +        while (true) {
  53.225 +            int current = getRaw(offset);
  53.226 +            if (compareAndSetRaw(offset, current, current + delta))
  53.227 +                return current;
  53.228 +        }
  53.229 +    }
  53.230 +
  53.231 +    /**
  53.232 +     * Atomically increments by one the element at index {@code i}.
  53.233 +     *
  53.234 +     * @param i the index
  53.235 +     * @return the updated value
  53.236 +     */
  53.237 +    public final int incrementAndGet(int i) {
  53.238 +        return addAndGet(i, 1);
  53.239 +    }
  53.240 +
  53.241 +    /**
  53.242 +     * Atomically decrements by one the element at index {@code i}.
  53.243 +     *
  53.244 +     * @param i the index
  53.245 +     * @return the updated value
  53.246 +     */
  53.247 +    public final int decrementAndGet(int i) {
  53.248 +        return addAndGet(i, -1);
  53.249 +    }
  53.250 +
  53.251 +    /**
  53.252 +     * Atomically adds the given value to the element at index {@code i}.
  53.253 +     *
  53.254 +     * @param i the index
  53.255 +     * @param delta the value to add
  53.256 +     * @return the updated value
  53.257 +     */
  53.258 +    public final int addAndGet(int i, int delta) {
  53.259 +        long offset = checkedByteOffset(i);
  53.260 +        while (true) {
  53.261 +            int current = getRaw(offset);
  53.262 +            int next = current + delta;
  53.263 +            if (compareAndSetRaw(offset, current, next))
  53.264 +                return next;
  53.265 +        }
  53.266 +    }
  53.267 +
  53.268 +    /**
  53.269 +     * Returns the String representation of the current values of array.
  53.270 +     * @return the String representation of the current values of array
  53.271 +     */
  53.272 +    public String toString() {
  53.273 +        int iMax = array.length - 1;
  53.274 +        if (iMax == -1)
  53.275 +            return "[]";
  53.276 +
  53.277 +        StringBuilder b = new StringBuilder();
  53.278 +        b.append('[');
  53.279 +        for (int i = 0; ; i++) {
  53.280 +            b.append(getRaw(byteOffset(i)));
  53.281 +            if (i == iMax)
  53.282 +                return b.append(']').toString();
  53.283 +            b.append(',').append(' ');
  53.284 +        }
  53.285 +    }
  53.286 +
  53.287 +}
    54.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    54.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLong.java	Thu Oct 03 15:40:35 2013 +0200
    54.3 @@ -0,0 +1,279 @@
    54.4 +/*
    54.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    54.6 + *
    54.7 + * This code is free software; you can redistribute it and/or modify it
    54.8 + * under the terms of the GNU General Public License version 2 only, as
    54.9 + * published by the Free Software Foundation.  Oracle designates this
   54.10 + * particular file as subject to the "Classpath" exception as provided
   54.11 + * by Oracle in the LICENSE file that accompanied this code.
   54.12 + *
   54.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   54.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   54.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   54.16 + * version 2 for more details (a copy is included in the LICENSE file that
   54.17 + * accompanied this code).
   54.18 + *
   54.19 + * You should have received a copy of the GNU General Public License version
   54.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   54.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   54.22 + *
   54.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   54.24 + * or visit www.oracle.com if you need additional information or have any
   54.25 + * questions.
   54.26 + */
   54.27 +
   54.28 +/*
   54.29 + * This file is available under and governed by the GNU General Public
   54.30 + * License version 2 only, as published by the Free Software Foundation.
   54.31 + * However, the following notice accompanied the original version of this
   54.32 + * file:
   54.33 + *
   54.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   54.35 + * Expert Group and released to the public domain, as explained at
   54.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   54.37 + */
   54.38 +
   54.39 +package java.util.concurrent.atomic;
   54.40 +import sun.misc.Unsafe;
   54.41 +
   54.42 +/**
   54.43 + * A {@code long} value that may be updated atomically.  See the
   54.44 + * {@link java.util.concurrent.atomic} package specification for
   54.45 + * description of the properties of atomic variables. An
   54.46 + * {@code AtomicLong} is used in applications such as atomically
   54.47 + * incremented sequence numbers, and cannot be used as a replacement
   54.48 + * for a {@link java.lang.Long}. However, this class does extend
   54.49 + * {@code Number} to allow uniform access by tools and utilities that
   54.50 + * deal with numerically-based classes.
   54.51 + *
   54.52 + * @since 1.5
   54.53 + * @author Doug Lea
   54.54 + */
   54.55 +public class AtomicLong extends Number implements java.io.Serializable {
   54.56 +    private static final long serialVersionUID = 1927816293512124184L;
   54.57 +
   54.58 +    // setup to use Unsafe.compareAndSwapLong for updates
   54.59 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   54.60 +    private static final long valueOffset;
   54.61 +
   54.62 +    /**
   54.63 +     * Records whether the underlying JVM supports lockless
   54.64 +     * compareAndSwap for longs. While the Unsafe.compareAndSwapLong
   54.65 +     * method works in either case, some constructions should be
   54.66 +     * handled at Java level to avoid locking user-visible locks.
   54.67 +     */
   54.68 +    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
   54.69 +
   54.70 +    /**
   54.71 +     * Returns whether underlying JVM supports lockless CompareAndSet
   54.72 +     * for longs. Called only once and cached in VM_SUPPORTS_LONG_CAS.
   54.73 +     */
   54.74 +    private static native boolean VMSupportsCS8();
   54.75 +
   54.76 +    static {
   54.77 +      try {
   54.78 +        valueOffset = unsafe.objectFieldOffset
   54.79 +            (AtomicLong.class.getDeclaredField("value"));
   54.80 +      } catch (Exception ex) { throw new Error(ex); }
   54.81 +    }
   54.82 +
   54.83 +    private volatile long value;
   54.84 +
   54.85 +    /**
   54.86 +     * Creates a new AtomicLong with the given initial value.
   54.87 +     *
   54.88 +     * @param initialValue the initial value
   54.89 +     */
   54.90 +    public AtomicLong(long initialValue) {
   54.91 +        value = initialValue;
   54.92 +    }
   54.93 +
   54.94 +    /**
   54.95 +     * Creates a new AtomicLong with initial value {@code 0}.
   54.96 +     */
   54.97 +    public AtomicLong() {
   54.98 +    }
   54.99 +
  54.100 +    /**
  54.101 +     * Gets the current value.
  54.102 +     *
  54.103 +     * @return the current value
  54.104 +     */
  54.105 +    public final long get() {
  54.106 +        return value;
  54.107 +    }
  54.108 +
  54.109 +    /**
  54.110 +     * Sets to the given value.
  54.111 +     *
  54.112 +     * @param newValue the new value
  54.113 +     */
  54.114 +    public final void set(long newValue) {
  54.115 +        value = newValue;
  54.116 +    }
  54.117 +
  54.118 +    /**
  54.119 +     * Eventually sets to the given value.
  54.120 +     *
  54.121 +     * @param newValue the new value
  54.122 +     * @since 1.6
  54.123 +     */
  54.124 +    public final void lazySet(long newValue) {
  54.125 +        unsafe.putOrderedLong(this, valueOffset, newValue);
  54.126 +    }
  54.127 +
  54.128 +    /**
  54.129 +     * Atomically sets to the given value and returns the old value.
  54.130 +     *
  54.131 +     * @param newValue the new value
  54.132 +     * @return the previous value
  54.133 +     */
  54.134 +    public final long getAndSet(long newValue) {
  54.135 +        while (true) {
  54.136 +            long current = get();
  54.137 +            if (compareAndSet(current, newValue))
  54.138 +                return current;
  54.139 +        }
  54.140 +    }
  54.141 +
  54.142 +    /**
  54.143 +     * Atomically sets the value to the given updated value
  54.144 +     * if the current value {@code ==} the expected value.
  54.145 +     *
  54.146 +     * @param expect the expected value
  54.147 +     * @param update the new value
  54.148 +     * @return true if successful. False return indicates that
  54.149 +     * the actual value was not equal to the expected value.
  54.150 +     */
  54.151 +    public final boolean compareAndSet(long expect, long update) {
  54.152 +        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
  54.153 +    }
  54.154 +
  54.155 +    /**
  54.156 +     * Atomically sets the value to the given updated value
  54.157 +     * if the current value {@code ==} the expected value.
  54.158 +     *
  54.159 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  54.160 +     * and does not provide ordering guarantees, so is only rarely an
  54.161 +     * appropriate alternative to {@code compareAndSet}.
  54.162 +     *
  54.163 +     * @param expect the expected value
  54.164 +     * @param update the new value
  54.165 +     * @return true if successful.
  54.166 +     */
  54.167 +    public final boolean weakCompareAndSet(long expect, long update) {
  54.168 +        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
  54.169 +    }
  54.170 +
  54.171 +    /**
  54.172 +     * Atomically increments by one the current value.
  54.173 +     *
  54.174 +     * @return the previous value
  54.175 +     */
  54.176 +    public final long getAndIncrement() {
  54.177 +        while (true) {
  54.178 +            long current = get();
  54.179 +            long next = current + 1;
  54.180 +            if (compareAndSet(current, next))
  54.181 +                return current;
  54.182 +        }
  54.183 +    }
  54.184 +
  54.185 +    /**
  54.186 +     * Atomically decrements by one the current value.
  54.187 +     *
  54.188 +     * @return the previous value
  54.189 +     */
  54.190 +    public final long getAndDecrement() {
  54.191 +        while (true) {
  54.192 +            long current = get();
  54.193 +            long next = current - 1;
  54.194 +            if (compareAndSet(current, next))
  54.195 +                return current;
  54.196 +        }
  54.197 +    }
  54.198 +
  54.199 +    /**
  54.200 +     * Atomically adds the given value to the current value.
  54.201 +     *
  54.202 +     * @param delta the value to add
  54.203 +     * @return the previous value
  54.204 +     */
  54.205 +    public final long getAndAdd(long delta) {
  54.206 +        while (true) {
  54.207 +            long current = get();
  54.208 +            long next = current + delta;
  54.209 +            if (compareAndSet(current, next))
  54.210 +                return current;
  54.211 +        }
  54.212 +    }
  54.213 +
  54.214 +    /**
  54.215 +     * Atomically increments by one the current value.
  54.216 +     *
  54.217 +     * @return the updated value
  54.218 +     */
  54.219 +    public final long incrementAndGet() {
  54.220 +        for (;;) {
  54.221 +            long current = get();
  54.222 +            long next = current + 1;
  54.223 +            if (compareAndSet(current, next))
  54.224 +                return next;
  54.225 +        }
  54.226 +    }
  54.227 +
  54.228 +    /**
  54.229 +     * Atomically decrements by one the current value.
  54.230 +     *
  54.231 +     * @return the updated value
  54.232 +     */
  54.233 +    public final long decrementAndGet() {
  54.234 +        for (;;) {
  54.235 +            long current = get();
  54.236 +            long next = current - 1;
  54.237 +            if (compareAndSet(current, next))
  54.238 +                return next;
  54.239 +        }
  54.240 +    }
  54.241 +
  54.242 +    /**
  54.243 +     * Atomically adds the given value to the current value.
  54.244 +     *
  54.245 +     * @param delta the value to add
  54.246 +     * @return the updated value
  54.247 +     */
  54.248 +    public final long addAndGet(long delta) {
  54.249 +        for (;;) {
  54.250 +            long current = get();
  54.251 +            long next = current + delta;
  54.252 +            if (compareAndSet(current, next))
  54.253 +                return next;
  54.254 +        }
  54.255 +    }
  54.256 +
  54.257 +    /**
  54.258 +     * Returns the String representation of the current value.
  54.259 +     * @return the String representation of the current value.
  54.260 +     */
  54.261 +    public String toString() {
  54.262 +        return Long.toString(get());
  54.263 +    }
  54.264 +
  54.265 +
  54.266 +    public int intValue() {
  54.267 +        return (int)get();
  54.268 +    }
  54.269 +
  54.270 +    public long longValue() {
  54.271 +        return get();
  54.272 +    }
  54.273 +
  54.274 +    public float floatValue() {
  54.275 +        return (float)get();
  54.276 +    }
  54.277 +
  54.278 +    public double doubleValue() {
  54.279 +        return (double)get();
  54.280 +    }
  54.281 +
  54.282 +}
    55.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    55.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicLongArray.java	Thu Oct 03 15:40:35 2013 +0200
    55.3 @@ -0,0 +1,284 @@
    55.4 +/*
    55.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    55.6 + *
    55.7 + * This code is free software; you can redistribute it and/or modify it
    55.8 + * under the terms of the GNU General Public License version 2 only, as
    55.9 + * published by the Free Software Foundation.  Oracle designates this
   55.10 + * particular file as subject to the "Classpath" exception as provided
   55.11 + * by Oracle in the LICENSE file that accompanied this code.
   55.12 + *
   55.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   55.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   55.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   55.16 + * version 2 for more details (a copy is included in the LICENSE file that
   55.17 + * accompanied this code).
   55.18 + *
   55.19 + * You should have received a copy of the GNU General Public License version
   55.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   55.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   55.22 + *
   55.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   55.24 + * or visit www.oracle.com if you need additional information or have any
   55.25 + * questions.
   55.26 + */
   55.27 +
   55.28 +/*
   55.29 + * This file is available under and governed by the GNU General Public
   55.30 + * License version 2 only, as published by the Free Software Foundation.
   55.31 + * However, the following notice accompanied the original version of this
   55.32 + * file:
   55.33 + *
   55.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   55.35 + * Expert Group and released to the public domain, as explained at
   55.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   55.37 + */
   55.38 +
   55.39 +package java.util.concurrent.atomic;
   55.40 +import sun.misc.Unsafe;
   55.41 +import java.util.*;
   55.42 +
   55.43 +/**
   55.44 + * A {@code long} array in which elements may be updated atomically.
   55.45 + * See the {@link java.util.concurrent.atomic} package specification
   55.46 + * for description of the properties of atomic variables.
   55.47 + * @since 1.5
   55.48 + * @author Doug Lea
   55.49 + */
   55.50 +public class AtomicLongArray implements java.io.Serializable {
   55.51 +    private static final long serialVersionUID = -2308431214976778248L;
   55.52 +
   55.53 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   55.54 +    private static final int base = unsafe.arrayBaseOffset(long[].class);
   55.55 +    private static final int shift;
   55.56 +    private final long[] array;
   55.57 +
   55.58 +    static {
   55.59 +        int scale = unsafe.arrayIndexScale(long[].class);
   55.60 +        if ((scale & (scale - 1)) != 0)
   55.61 +            throw new Error("data type scale not a power of two");
   55.62 +        shift = 31 - Integer.numberOfLeadingZeros(scale);
   55.63 +    }
   55.64 +
   55.65 +    private long checkedByteOffset(int i) {
   55.66 +        if (i < 0 || i >= array.length)
   55.67 +            throw new IndexOutOfBoundsException("index " + i);
   55.68 +
   55.69 +        return byteOffset(i);
   55.70 +    }
   55.71 +
   55.72 +    private static long byteOffset(int i) {
   55.73 +        return ((long) i << shift) + base;
   55.74 +    }
   55.75 +
   55.76 +    /**
   55.77 +     * Creates a new AtomicLongArray of the given length, with all
   55.78 +     * elements initially zero.
   55.79 +     *
   55.80 +     * @param length the length of the array
   55.81 +     */
   55.82 +    public AtomicLongArray(int length) {
   55.83 +        array = new long[length];
   55.84 +    }
   55.85 +
   55.86 +    /**
   55.87 +     * Creates a new AtomicLongArray with the same length as, and
   55.88 +     * all elements copied from, the given array.
   55.89 +     *
   55.90 +     * @param array the array to copy elements from
   55.91 +     * @throws NullPointerException if array is null
   55.92 +     */
   55.93 +    public AtomicLongArray(long[] array) {
   55.94 +        // Visibility guaranteed by final field guarantees
   55.95 +        this.array = array.clone();
   55.96 +    }
   55.97 +
   55.98 +    /**
   55.99 +     * Returns the length of the array.
  55.100 +     *
  55.101 +     * @return the length of the array
  55.102 +     */
  55.103 +    public final int length() {
  55.104 +        return array.length;
  55.105 +    }
  55.106 +
  55.107 +    /**
  55.108 +     * Gets the current value at position {@code i}.
  55.109 +     *
  55.110 +     * @param i the index
  55.111 +     * @return the current value
  55.112 +     */
  55.113 +    public final long get(int i) {
  55.114 +        return getRaw(checkedByteOffset(i));
  55.115 +    }
  55.116 +
  55.117 +    private long getRaw(long offset) {
  55.118 +        return unsafe.getLongVolatile(array, offset);
  55.119 +    }
  55.120 +
  55.121 +    /**
  55.122 +     * Sets the element at position {@code i} to the given value.
  55.123 +     *
  55.124 +     * @param i the index
  55.125 +     * @param newValue the new value
  55.126 +     */
  55.127 +    public final void set(int i, long newValue) {
  55.128 +        unsafe.putLongVolatile(array, checkedByteOffset(i), newValue);
  55.129 +    }
  55.130 +
  55.131 +    /**
  55.132 +     * Eventually sets the element at position {@code i} to the given value.
  55.133 +     *
  55.134 +     * @param i the index
  55.135 +     * @param newValue the new value
  55.136 +     * @since 1.6
  55.137 +     */
  55.138 +    public final void lazySet(int i, long newValue) {
  55.139 +        unsafe.putOrderedLong(array, checkedByteOffset(i), newValue);
  55.140 +    }
  55.141 +
  55.142 +
  55.143 +    /**
  55.144 +     * Atomically sets the element at position {@code i} to the given value
  55.145 +     * and returns the old value.
  55.146 +     *
  55.147 +     * @param i the index
  55.148 +     * @param newValue the new value
  55.149 +     * @return the previous value
  55.150 +     */
  55.151 +    public final long getAndSet(int i, long newValue) {
  55.152 +        long offset = checkedByteOffset(i);
  55.153 +        while (true) {
  55.154 +            long current = getRaw(offset);
  55.155 +            if (compareAndSetRaw(offset, current, newValue))
  55.156 +                return current;
  55.157 +        }
  55.158 +    }
  55.159 +
  55.160 +    /**
  55.161 +     * Atomically sets the element at position {@code i} to the given
  55.162 +     * updated value if the current value {@code ==} the expected value.
  55.163 +     *
  55.164 +     * @param i the index
  55.165 +     * @param expect the expected value
  55.166 +     * @param update the new value
  55.167 +     * @return true if successful. False return indicates that
  55.168 +     * the actual value was not equal to the expected value.
  55.169 +     */
  55.170 +    public final boolean compareAndSet(int i, long expect, long update) {
  55.171 +        return compareAndSetRaw(checkedByteOffset(i), expect, update);
  55.172 +    }
  55.173 +
  55.174 +    private boolean compareAndSetRaw(long offset, long expect, long update) {
  55.175 +        return unsafe.compareAndSwapLong(array, offset, expect, update);
  55.176 +    }
  55.177 +
  55.178 +    /**
  55.179 +     * Atomically sets the element at position {@code i} to the given
  55.180 +     * updated value if the current value {@code ==} the expected value.
  55.181 +     *
  55.182 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  55.183 +     * and does not provide ordering guarantees, so is only rarely an
  55.184 +     * appropriate alternative to {@code compareAndSet}.
  55.185 +     *
  55.186 +     * @param i the index
  55.187 +     * @param expect the expected value
  55.188 +     * @param update the new value
  55.189 +     * @return true if successful.
  55.190 +     */
  55.191 +    public final boolean weakCompareAndSet(int i, long expect, long update) {
  55.192 +        return compareAndSet(i, expect, update);
  55.193 +    }
  55.194 +
  55.195 +    /**
  55.196 +     * Atomically increments by one the element at index {@code i}.
  55.197 +     *
  55.198 +     * @param i the index
  55.199 +     * @return the previous value
  55.200 +     */
  55.201 +    public final long getAndIncrement(int i) {
  55.202 +        return getAndAdd(i, 1);
  55.203 +    }
  55.204 +
  55.205 +    /**
  55.206 +     * Atomically decrements by one the element at index {@code i}.
  55.207 +     *
  55.208 +     * @param i the index
  55.209 +     * @return the previous value
  55.210 +     */
  55.211 +    public final long getAndDecrement(int i) {
  55.212 +        return getAndAdd(i, -1);
  55.213 +    }
  55.214 +
  55.215 +    /**
  55.216 +     * Atomically adds the given value to the element at index {@code i}.
  55.217 +     *
  55.218 +     * @param i the index
  55.219 +     * @param delta the value to add
  55.220 +     * @return the previous value
  55.221 +     */
  55.222 +    public final long getAndAdd(int i, long delta) {
  55.223 +        long offset = checkedByteOffset(i);
  55.224 +        while (true) {
  55.225 +            long current = getRaw(offset);
  55.226 +            if (compareAndSetRaw(offset, current, current + delta))
  55.227 +                return current;
  55.228 +        }
  55.229 +    }
  55.230 +
  55.231 +    /**
  55.232 +     * Atomically increments by one the element at index {@code i}.
  55.233 +     *
  55.234 +     * @param i the index
  55.235 +     * @return the updated value
  55.236 +     */
  55.237 +    public final long incrementAndGet(int i) {
  55.238 +        return addAndGet(i, 1);
  55.239 +    }
  55.240 +
  55.241 +    /**
  55.242 +     * Atomically decrements by one the element at index {@code i}.
  55.243 +     *
  55.244 +     * @param i the index
  55.245 +     * @return the updated value
  55.246 +     */
  55.247 +    public final long decrementAndGet(int i) {
  55.248 +        return addAndGet(i, -1);
  55.249 +    }
  55.250 +
  55.251 +    /**
  55.252 +     * Atomically adds the given value to the element at index {@code i}.
  55.253 +     *
  55.254 +     * @param i the index
  55.255 +     * @param delta the value to add
  55.256 +     * @return the updated value
  55.257 +     */
  55.258 +    public long addAndGet(int i, long delta) {
  55.259 +        long offset = checkedByteOffset(i);
  55.260 +        while (true) {
  55.261 +            long current = getRaw(offset);
  55.262 +            long next = current + delta;
  55.263 +            if (compareAndSetRaw(offset, current, next))
  55.264 +                return next;
  55.265 +        }
  55.266 +    }
  55.267 +
  55.268 +    /**
  55.269 +     * Returns the String representation of the current values of array.
  55.270 +     * @return the String representation of the current values of array
  55.271 +     */
  55.272 +    public String toString() {
  55.273 +        int iMax = array.length - 1;
  55.274 +        if (iMax == -1)
  55.275 +            return "[]";
  55.276 +
  55.277 +        StringBuilder b = new StringBuilder();
  55.278 +        b.append('[');
  55.279 +        for (int i = 0; ; i++) {
  55.280 +            b.append(getRaw(byteOffset(i)));
  55.281 +            if (i == iMax)
  55.282 +                return b.append(']').toString();
  55.283 +            b.append(',').append(' ');
  55.284 +        }
  55.285 +    }
  55.286 +
  55.287 +}
    56.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    56.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReference.java	Thu Oct 03 15:40:35 2013 +0200
    56.3 @@ -0,0 +1,155 @@
    56.4 +/*
    56.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    56.6 + *
    56.7 + * This code is free software; you can redistribute it and/or modify it
    56.8 + * under the terms of the GNU General Public License version 2 only, as
    56.9 + * published by the Free Software Foundation.  Oracle designates this
   56.10 + * particular file as subject to the "Classpath" exception as provided
   56.11 + * by Oracle in the LICENSE file that accompanied this code.
   56.12 + *
   56.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   56.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   56.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   56.16 + * version 2 for more details (a copy is included in the LICENSE file that
   56.17 + * accompanied this code).
   56.18 + *
   56.19 + * You should have received a copy of the GNU General Public License version
   56.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   56.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   56.22 + *
   56.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   56.24 + * or visit www.oracle.com if you need additional information or have any
   56.25 + * questions.
   56.26 + */
   56.27 +
   56.28 +/*
   56.29 + * This file is available under and governed by the GNU General Public
   56.30 + * License version 2 only, as published by the Free Software Foundation.
   56.31 + * However, the following notice accompanied the original version of this
   56.32 + * file:
   56.33 + *
   56.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   56.35 + * Expert Group and released to the public domain, as explained at
   56.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   56.37 + */
   56.38 +
   56.39 +package java.util.concurrent.atomic;
   56.40 +import sun.misc.Unsafe;
   56.41 +
   56.42 +/**
   56.43 + * An object reference that may be updated atomically. See the {@link
   56.44 + * java.util.concurrent.atomic} package specification for description
   56.45 + * of the properties of atomic variables.
   56.46 + * @since 1.5
   56.47 + * @author Doug Lea
   56.48 + * @param <V> The type of object referred to by this reference
   56.49 + */
   56.50 +public class AtomicReference<V>  implements java.io.Serializable {
   56.51 +    private static final long serialVersionUID = -1848883965231344442L;
   56.52 +
   56.53 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   56.54 +    private static final long valueOffset;
   56.55 +
   56.56 +    static {
   56.57 +      try {
   56.58 +        valueOffset = unsafe.objectFieldOffset
   56.59 +            (AtomicReference.class.getDeclaredField("value"));
   56.60 +      } catch (Exception ex) { throw new Error(ex); }
   56.61 +    }
   56.62 +
   56.63 +    private volatile V value;
   56.64 +
   56.65 +    /**
   56.66 +     * Creates a new AtomicReference with the given initial value.
   56.67 +     *
   56.68 +     * @param initialValue the initial value
   56.69 +     */
   56.70 +    public AtomicReference(V initialValue) {
   56.71 +        value = initialValue;
   56.72 +    }
   56.73 +
   56.74 +    /**
   56.75 +     * Creates a new AtomicReference with null initial value.
   56.76 +     */
   56.77 +    public AtomicReference() {
   56.78 +    }
   56.79 +
   56.80 +    /**
   56.81 +     * Gets the current value.
   56.82 +     *
   56.83 +     * @return the current value
   56.84 +     */
   56.85 +    public final V get() {
   56.86 +        return value;
   56.87 +    }
   56.88 +
   56.89 +    /**
   56.90 +     * Sets to the given value.
   56.91 +     *
   56.92 +     * @param newValue the new value
   56.93 +     */
   56.94 +    public final void set(V newValue) {
   56.95 +        value = newValue;
   56.96 +    }
   56.97 +
   56.98 +    /**
   56.99 +     * Eventually sets to the given value.
  56.100 +     *
  56.101 +     * @param newValue the new value
  56.102 +     * @since 1.6
  56.103 +     */
  56.104 +    public final void lazySet(V newValue) {
  56.105 +        unsafe.putOrderedObject(this, valueOffset, newValue);
  56.106 +    }
  56.107 +
  56.108 +    /**
  56.109 +     * Atomically sets the value to the given updated value
  56.110 +     * if the current value {@code ==} the expected value.
  56.111 +     * @param expect the expected value
  56.112 +     * @param update the new value
  56.113 +     * @return true if successful. False return indicates that
  56.114 +     * the actual value was not equal to the expected value.
  56.115 +     */
  56.116 +    public final boolean compareAndSet(V expect, V update) {
  56.117 +        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
  56.118 +    }
  56.119 +
  56.120 +    /**
  56.121 +     * Atomically sets the value to the given updated value
  56.122 +     * if the current value {@code ==} the expected value.
  56.123 +     *
  56.124 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  56.125 +     * and does not provide ordering guarantees, so is only rarely an
  56.126 +     * appropriate alternative to {@code compareAndSet}.
  56.127 +     *
  56.128 +     * @param expect the expected value
  56.129 +     * @param update the new value
  56.130 +     * @return true if successful.
  56.131 +     */
  56.132 +    public final boolean weakCompareAndSet(V expect, V update) {
  56.133 +        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
  56.134 +    }
  56.135 +
  56.136 +    /**
  56.137 +     * Atomically sets to the given value and returns the old value.
  56.138 +     *
  56.139 +     * @param newValue the new value
  56.140 +     * @return the previous value
  56.141 +     */
  56.142 +    public final V getAndSet(V newValue) {
  56.143 +        while (true) {
  56.144 +            V x = get();
  56.145 +            if (compareAndSet(x, newValue))
  56.146 +                return x;
  56.147 +        }
  56.148 +    }
  56.149 +
  56.150 +    /**
  56.151 +     * Returns the String representation of the current value.
  56.152 +     * @return the String representation of the current value.
  56.153 +     */
  56.154 +    public String toString() {
  56.155 +        return String.valueOf(get());
  56.156 +    }
  56.157 +
  56.158 +}
    57.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    57.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/AtomicReferenceArray.java	Thu Oct 03 15:40:35 2013 +0200
    57.3 @@ -0,0 +1,213 @@
    57.4 +/*
    57.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    57.6 + *
    57.7 + * This code is free software; you can redistribute it and/or modify it
    57.8 + * under the terms of the GNU General Public License version 2 only, as
    57.9 + * published by the Free Software Foundation.  Oracle designates this
   57.10 + * particular file as subject to the "Classpath" exception as provided
   57.11 + * by Oracle in the LICENSE file that accompanied this code.
   57.12 + *
   57.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   57.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   57.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   57.16 + * version 2 for more details (a copy is included in the LICENSE file that
   57.17 + * accompanied this code).
   57.18 + *
   57.19 + * You should have received a copy of the GNU General Public License version
   57.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   57.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   57.22 + *
   57.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   57.24 + * or visit www.oracle.com if you need additional information or have any
   57.25 + * questions.
   57.26 + */
   57.27 +
   57.28 +/*
   57.29 + * This file is available under and governed by the GNU General Public
   57.30 + * License version 2 only, as published by the Free Software Foundation.
   57.31 + * However, the following notice accompanied the original version of this
   57.32 + * file:
   57.33 + *
   57.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   57.35 + * Expert Group and released to the public domain, as explained at
   57.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   57.37 + */
   57.38 +
   57.39 +package java.util.concurrent.atomic;
   57.40 +import sun.misc.Unsafe;
   57.41 +import java.util.*;
   57.42 +
   57.43 +/**
   57.44 + * An array of object references in which elements may be updated
   57.45 + * atomically.  See the {@link java.util.concurrent.atomic} package
   57.46 + * specification for description of the properties of atomic
   57.47 + * variables.
   57.48 + * @since 1.5
   57.49 + * @author Doug Lea
   57.50 + * @param <E> The base class of elements held in this array
   57.51 + */
   57.52 +public class AtomicReferenceArray<E> implements java.io.Serializable {
   57.53 +    private static final long serialVersionUID = -6209656149925076980L;
   57.54 +
   57.55 +    private static final Unsafe unsafe = Unsafe.getUnsafe();
   57.56 +    private static final int base = unsafe.arrayBaseOffset(Object[].class);
   57.57 +    private static final int shift;
   57.58 +    private final Object[] array;
   57.59 +
   57.60 +    static {
   57.61 +        int scale = unsafe.arrayIndexScale(Object[].class);
   57.62 +        if ((scale & (scale - 1)) != 0)
   57.63 +            throw new Error("data type scale not a power of two");
   57.64 +        shift = 31 - Integer.numberOfLeadingZeros(scale);
   57.65 +    }
   57.66 +
   57.67 +    private long checkedByteOffset(int i) {
   57.68 +        if (i < 0 || i >= array.length)
   57.69 +            throw new IndexOutOfBoundsException("index " + i);
   57.70 +
   57.71 +        return byteOffset(i);
   57.72 +    }
   57.73 +
   57.74 +    private static long byteOffset(int i) {
   57.75 +        return ((long) i << shift) + base;
   57.76 +    }
   57.77 +
   57.78 +    /**
   57.79 +     * Creates a new AtomicReferenceArray of the given length, with all
   57.80 +     * elements initially null.
   57.81 +     *
   57.82 +     * @param length the length of the array
   57.83 +     */
   57.84 +    public AtomicReferenceArray(int length) {
   57.85 +        array = new Object[length];
   57.86 +    }
   57.87 +
   57.88 +    /**
   57.89 +     * Creates a new AtomicReferenceArray with the same length as, and
   57.90 +     * all elements copied from, the given array.
   57.91 +     *
   57.92 +     * @param array the array to copy elements from
   57.93 +     * @throws NullPointerException if array is null
   57.94 +     */
   57.95 +    public AtomicReferenceArray(E[] array) {
   57.96 +        // Visibility guaranteed by final field guarantees
   57.97 +        this.array = array.clone();
   57.98 +    }
   57.99 +
  57.100 +    /**
  57.101 +     * Returns the length of the array.
  57.102 +     *
  57.103 +     * @return the length of the array
  57.104 +     */
  57.105 +    public final int length() {
  57.106 +        return array.length;
  57.107 +    }
  57.108 +
  57.109 +    /**
  57.110 +     * Gets the current value at position {@code i}.
  57.111 +     *
  57.112 +     * @param i the index
  57.113 +     * @return the current value
  57.114 +     */
  57.115 +    public final E get(int i) {
  57.116 +        return getRaw(checkedByteOffset(i));
  57.117 +    }
  57.118 +
  57.119 +    private E getRaw(long offset) {
  57.120 +        return (E) unsafe.getObjectVolatile(array, offset);
  57.121 +    }
  57.122 +
  57.123 +    /**
  57.124 +     * Sets the element at position {@code i} to the given value.
  57.125 +     *
  57.126 +     * @param i the index
  57.127 +     * @param newValue the new value
  57.128 +     */
  57.129 +    public final void set(int i, E newValue) {
  57.130 +        unsafe.putObjectVolatile(array, checkedByteOffset(i), newValue);
  57.131 +    }
  57.132 +
  57.133 +    /**
  57.134 +     * Eventually sets the element at position {@code i} to the given value.
  57.135 +     *
  57.136 +     * @param i the index
  57.137 +     * @param newValue the new value
  57.138 +     * @since 1.6
  57.139 +     */
  57.140 +    public final void lazySet(int i, E newValue) {
  57.141 +        unsafe.putOrderedObject(array, checkedByteOffset(i), newValue);
  57.142 +    }
  57.143 +
  57.144 +
  57.145 +    /**
  57.146 +     * Atomically sets the element at position {@code i} to the given
  57.147 +     * value and returns the old value.
  57.148 +     *
  57.149 +     * @param i the index
  57.150 +     * @param newValue the new value
  57.151 +     * @return the previous value
  57.152 +     */
  57.153 +    public final E getAndSet(int i, E newValue) {
  57.154 +        long offset = checkedByteOffset(i);
  57.155 +        while (true) {
  57.156 +            E current = (E) getRaw(offset);
  57.157 +            if (compareAndSetRaw(offset, current, newValue))
  57.158 +                return current;
  57.159 +        }
  57.160 +    }
  57.161 +
  57.162 +    /**
  57.163 +     * Atomically sets the element at position {@code i} to the given
  57.164 +     * updated value if the current value {@code ==} the expected value.
  57.165 +     *
  57.166 +     * @param i the index
  57.167 +     * @param expect the expected value
  57.168 +     * @param update the new value
  57.169 +     * @return true if successful. False return indicates that
  57.170 +     * the actual value was not equal to the expected value.
  57.171 +     */
  57.172 +    public final boolean compareAndSet(int i, E expect, E update) {
  57.173 +        return compareAndSetRaw(checkedByteOffset(i), expect, update);
  57.174 +    }
  57.175 +
  57.176 +    private boolean compareAndSetRaw(long offset, E expect, E update) {
  57.177 +        return unsafe.compareAndSwapObject(array, offset, expect, update);
  57.178 +    }
  57.179 +
  57.180 +    /**
  57.181 +     * Atomically sets the element at position {@code i} to the given
  57.182 +     * updated value if the current value {@code ==} the expected value.
  57.183 +     *
  57.184 +     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
  57.185 +     * and does not provide ordering guarantees, so is only rarely an
  57.186 +     * appropriate alternative to {@code compareAndSet}.
  57.187 +     *
  57.188 +     * @param i the index
  57.189 +     * @param expect the expected value
  57.190 +     * @param update the new value
  57.191 +     * @return true if successful.
  57.192 +     */
  57.193 +    public final boolean weakCompareAndSet(int i, E expect, E update) {
  57.194 +        return compareAndSet(i, expect, update);
  57.195 +    }
  57.196 +
  57.197 +    /**
  57.198 +     * Returns the String representation of the current values of array.
  57.199 +     * @return the String representation of the current values of array
  57.200 +     */
  57.201 +    public String toString() {
  57.202 +           int iMax = array.length - 1;
  57.203 +        if (iMax == -1)
  57.204 +            return "[]";
  57.205 +
  57.206 +        StringBuilder b = new StringBuilder();
  57.207 +        b.append('[');
  57.208 +        for (int i = 0; ; i++) {
  57.209 +            b.append(getRaw(byteOffset(i)));
  57.210 +            if (i == iMax)
  57.211 +                return b.append(']').toString();
  57.212 +            b.append(',').append(' ');
  57.213 +        }
  57.214 +    }
  57.215 +
  57.216 +}
    58.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    58.2 +++ b/rt/emul/compact/src/main/java/java/util/concurrent/atomic/package-info.java	Thu Oct 03 15:40:35 2013 +0200
    58.3 @@ -0,0 +1,199 @@
    58.4 +/*
    58.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    58.6 + *
    58.7 + * This code is free software; you can redistribute it and/or modify it
    58.8 + * under the terms of the GNU General Public License version 2 only, as
    58.9 + * published by the Free Software Foundation.  Oracle designates this
   58.10 + * particular file as subject to the "Classpath" exception as provided
   58.11 + * by Oracle in the LICENSE file that accompanied this code.
   58.12 + *
   58.13 + * This code is distributed in the hope that it will be useful, but WITHOUT
   58.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   58.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   58.16 + * version 2 for more details (a copy is included in the LICENSE file that
   58.17 + * accompanied this code).
   58.18 + *
   58.19 + * You should have received a copy of the GNU General Public License version
   58.20 + * 2 along with this work; if not, write to the Free Software Foundation,
   58.21 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   58.22 + *
   58.23 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   58.24 + * or visit www.oracle.com if you need additional information or have any
   58.25 + * questions.
   58.26 + */
   58.27 +
   58.28 +/*
   58.29 + * This file is available under and governed by the GNU General Public
   58.30 + * License version 2 only, as published by the Free Software Foundation.
   58.31 + * However, the following notice accompanied the original version of this
   58.32 + * file:
   58.33 + *
   58.34 + * Written by Doug Lea with assistance from members of JCP JSR-166
   58.35 + * Expert Group and released to the public domain, as explained at
   58.36 + * http://creativecommons.org/publicdomain/zero/1.0/
   58.37 + */
   58.38 +
   58.39 +/**
   58.40 + * A small toolkit of classes that support lock-free thread-safe
   58.41 + * programming on single variables.  In essence, the classes in this
   58.42 + * package extend the notion of {@code volatile} values, fields, and
   58.43 + * array elements to those that also provide an atomic conditional update
   58.44 + * operation of the form:
   58.45 + *
   58.46 + * <pre>
   58.47 + *   boolean compareAndSet(expectedValue, updateValue);
   58.48 + * </pre>
   58.49 + *
   58.50 + * <p>This method (which varies in argument types across different
   58.51 + * classes) atomically sets a variable to the {@code updateValue} if it
   58.52 + * currently holds the {@code expectedValue}, reporting {@code true} on
   58.53 + * success.  The classes in this package also contain methods to get and
   58.54 + * unconditionally set values, as well as a weaker conditional atomic
   58.55 + * update operation {@code weakCompareAndSet} described below.
   58.56 + *
   58.57 + * <p>The specifications of these methods enable implementations to
   58.58 + * employ efficient machine-level atomic instructions that are available
   58.59 + * on contemporary processors.  However on some platforms, support may
   58.60 + * entail some form of internal locking.  Thus the methods are not
   58.61 + * strictly guaranteed to be non-blocking --
   58.62 + * a thread may block transiently before performing the operation.
   58.63 + *
   58.64 + * <p>Instances of classes
   58.65 + * {@link java.util.concurrent.atomic.AtomicBoolean},
   58.66 + * {@link java.util.concurrent.atomic.AtomicInteger},
   58.67 + * {@link java.util.concurrent.atomic.AtomicLong}, and
   58.68 + * {@link java.util.concurrent.atomic.AtomicReference}
   58.69 + * each provide access and updates to a single variable of the
   58.70 + * corresponding type.  Each class also provides appropriate utility
   58.71 + * methods for that type.  For example, classes {@code AtomicLong} and
   58.72 + * {@code AtomicInteger} provide atomic increment methods.  One
   58.73 + * application is to generate sequence numbers, as in:
   58.74 + *
   58.75 + * <pre>
   58.76 + * class Sequencer {
   58.77 + *   private final AtomicLong sequenceNumber
   58.78 + *     = new AtomicLong(0);
   58.79 + *   public long next() {
   58.80 + *     return sequenceNumber.getAndIncrement();
   58.81 + *   }
   58.82 + * }
   58.83 + * </pre>
   58.84 + *
   58.85 + * <p>The memory effects for accesses and updates of atomics generally
   58.86 + * follow the rules for volatiles, as stated in section 17.4 of
   58.87 + * <cite>The Java&trade; Language Specification</cite>.
   58.88 + *
   58.89 + * <ul>
   58.90 + *
   58.91 + *   <li> {@code get} has the memory effects of reading a
   58.92 + * {@code volatile} variable.
   58.93 + *
   58.94 + *   <li> {@code set} has the memory effects of writing (assigning) a
   58.95 + * {@code volatile} variable.
   58.96 + *
   58.97 + *   <li> {@code lazySet} has the memory effects of writing (assigning)
   58.98 + *   a {@code volatile} variable except that it permits reorderings with
   58.99 + *   subsequent (but not previous) memory actions that do not themselves
  58.100 + *   impose reordering constraints with ordinary non-{@code volatile}
  58.101 + *   writes.  Among other usage contexts, {@code lazySet} may apply when
  58.102 + *   nulling out, for the sake of garbage collection, a reference that is
  58.103 + *   never accessed again.
  58.104 + *
  58.105 + *   <li>{@code weakCompareAndSet} atomically reads and conditionally
  58.106 + *   writes a variable but does <em>not</em>
  58.107 + *   create any happens-before orderings, so provides no guarantees
  58.108 + *   with respect to previous or subsequent reads and writes of any
  58.109 + *   variables other than the target of the {@code weakCompareAndSet}.
  58.110 + *
  58.111 + *   <li> {@code compareAndSet}
  58.112 + *   and all other read-and-update operations such as {@code getAndIncrement}
  58.113 + *   have the memory effects of both reading and
  58.114 + *   writing {@code volatile} variables.
  58.115 + * </ul>
  58.116 + *
  58.117 + * <p>In addition to classes representing single values, this package
  58.118 + * contains <em>Updater</em> classes that can be used to obtain
  58.119 + * {@code compareAndSet} operations on any selected {@code volatile}
  58.120 + * field of any selected class.
  58.121 + *
  58.122 + * {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater},
  58.123 + * {@link java.util.concurrent.atomic.AtomicIntegerFieldUpdater}, and
  58.124 + * {@link java.util.concurrent.atomic.AtomicLongFieldUpdater} are
  58.125 + * reflection-based utilities that provide access to the associated
  58.126 + * field types.  These are mainly of use in atomic data structures in
  58.127 + * which several {@code volatile} fields of the same node (for
  58.128 + * example, the links of a tree node) are independently subject to
  58.129 + * atomic updates.  These classes enable greater flexibility in how
  58.130 + * and when to use atomic updates, at the expense of more awkward
  58.131 + * reflection-based setup, less convenient usage, and weaker
  58.132 + * guarantees.
  58.133 + *
  58.134 + * <p>The
  58.135 + * {@link java.util.concurrent.atomic.AtomicIntegerArray},
  58.136 + * {@link java.util.concurrent.atomic.AtomicLongArray}, and
  58.137 + * {@link java.util.concurrent.atomic.AtomicReferenceArray} classes
  58.138 + * further extend atomic operation support to arrays of these types.
  58.139 + * These classes are also notable in providing {@code volatile} access
  58.140 + * semantics for their array elements, which is not supported for
  58.141 + * ordinary arrays.
  58.142 + *
  58.143 + * <a name="Spurious">
  58.144 + * <p>The atomic classes also support method {@code weakCompareAndSet},
  58.145 + * which has limited applicability.  On some platforms, the weak version
  58.146 + * may be more efficient than {@code compareAndSet} in the normal case,
  58.147 + * but differs in that any given invocation of the
  58.148 + * {@code weakCompareAndSet} method may return {@code false}
  58.149 + * <em>spuriously</em> (that is, for no apparent reason)</a>.  A
  58.150 + * {@code false} return means only that the operation may be retried if
  58.151 + * desired, relying on the guarantee that repeated invocation when the
  58.152 + * variable holds {@code expectedValue} and no other thread is also
  58.153 + * attempting to set the variable will eventually succeed.  (Such
  58.154 + * spurious failures may for example be due to memory contention effects
  58.155 + * that are unrelated to whether the expected and current values are
  58.156 + * equal.)  Additionally {@code weakCompareAndSet} does not provide
  58.157 + * ordering guarantees that are usually needed for synchronization
  58.158 + * control.  However, the method may be useful for updating counters and
  58.159 + * statistics when such updates are unrelated to the other
  58.160 + * happens-before orderings of a program.  When a thread sees an update
  58.161 + * to an atomic variable caused by a {@code weakCompareAndSet}, it does
  58.162 + * not necessarily see updates to any <em>other</em> variables that
  58.163 + * occurred before the {@code weakCompareAndSet}.  This may be
  58.164 + * acceptable when, for example, updating performance statistics, but
  58.165 + * rarely otherwise.
  58.166 + *
  58.167 + * <p>The {@link java.util.concurrent.atomic.AtomicMarkableReference}
  58.168 + * class associates a single boolean with a reference.  For example, this
  58.169 + * bit might be used inside a data structure to mean that the object
  58.170 + * being referenced has logically been deleted.
  58.171 + *
  58.172 + * The {@link java.util.concurrent.atomic.AtomicStampedReference}
  58.173 + * class associates an integer value with a reference.  This may be
  58.174 + * used for example, to represent version numbers corresponding to
  58.175 + * series of updates.
  58.176 + *
  58.177 + * <p>Atomic classes are designed primarily as building blocks for
  58.178 + * implementing non-blocking data structures and related infrastructure
  58.179 + * classes.  The {@code compareAndSet} method is not a general
  58.180 + * replacement for locking.  It applies only when critical updates for an
  58.181 + * object are confined to a <em>single</em> variable.
  58.182 + *
  58.183 + * <p>Atomic classes are not general purpose replacements for
  58.184 + * {@code java.lang.Integer} and related classes.  They do <em>not</em>
  58.185 + * define methods such as {@code hashCode} and
  58.186 + * {@code compareTo}.  (Because atomic variables are expected to be
  58.187 + * mutated, they are poor choices for hash table keys.)  Additionally,
  58.188 + * classes are provided only for those types that are commonly useful in
  58.189 + * intended applications.  For example, there is no atomic class for
  58.190 + * representing {@code byte}.  In those infrequent cases where you would
  58.191 + * like to do so, you can use an {@code AtomicInteger} to hold
  58.192 + * {@code byte} values, and cast appropriately.
  58.193 + *
  58.194 + * You can also hold floats using
  58.195 + * {@link java.lang.Float#floatToIntBits} and
  58.196 + * {@link java.lang.Float#intBitsToFloat} conversions, and doubles using
  58.197 + * {@link java.lang.Double#doubleToLongBits} and
  58.198 + * {@link java.lang.Double#longBitsToDouble} conversions.
  58.199 + *
  58.200 + * @since 1.5
  58.201 + */
  58.202 +package java.util.concurrent.atomic;