diff options
Diffstat (limited to 'gcc-4.2.1/libjava/java')
115 files changed, 52836 insertions, 0 deletions
diff --git a/gcc-4.2.1/libjava/java/io/BufferedInputStream.java b/gcc-4.2.1/libjava/java/io/BufferedInputStream.java new file mode 100644 index 000000000..36e58f636 --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/BufferedInputStream.java @@ -0,0 +1,390 @@ +/* BufferedInputStream.java -- An input stream that implements buffering + Copyright (C) 1998, 1999, 2001, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +/** + * This subclass of <code>FilterInputStream</code> buffers input from an + * underlying implementation to provide a possibly more efficient read + * mechanism. It maintains the buffer and buffer state in instance + * variables that are available to subclasses. The default buffer size + * of 2048 bytes can be overridden by the creator of the stream. + * <p> + * This class also implements mark/reset functionality. It is capable + * of remembering any number of input bytes, to the limits of + * system memory or the size of <code>Integer.MAX_VALUE</code> + * <p> + * Please note that this class does not properly handle character + * encodings. Consider using the <code>BufferedReader</code> class which + * does. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * @author Jeroen Frijters (jeroen@frijters.net) + */ +public class BufferedInputStream extends FilterInputStream +{ + + /** + * This is the default buffer size + */ + private static final int DEFAULT_BUFFER_SIZE = 2048; + + /** + * The buffer used for storing data from the underlying stream. + */ + protected byte[] buf; + + /** + * The number of valid bytes currently in the buffer. It is also the index + * of the buffer position one byte past the end of the valid data. + */ + protected int count; + + /** + * The index of the next character that will by read from the buffer. + * When <code>pos == count</code>, the buffer is empty. + */ + protected int pos; + + /** + * The value of <code>pos</code> when the <code>mark()</code> method was + * called. + * This is set to -1 if there is no mark set. + */ + protected int markpos = -1; + + /** + * This is the maximum number of bytes than can be read after a + * call to <code>mark()</code> before the mark can be discarded. + * After this may bytes are read, the <code>reset()</code> method + * may not be called successfully. + */ + protected int marklimit; + + /** + * This is the initial buffer size. When the buffer is grown because + * of marking requirements, it will be grown by bufferSize increments. + * The underlying stream will be read in chunks of bufferSize. + */ + private final int bufferSize; + + /** + * This method initializes a new <code>BufferedInputStream</code> that will + * read from the specified subordinate stream with a default buffer size + * of 2048 bytes + * + * @param in The subordinate stream to read from + */ + public BufferedInputStream(InputStream in) + { + this(in, DEFAULT_BUFFER_SIZE); + } + + /** + * This method initializes a new <code>BufferedInputStream</code> that will + * read from the specified subordinate stream with a buffer size that + * is specified by the caller. + * + * @param in The subordinate stream to read from + * @param size The buffer size to use + * + * @exception IllegalArgumentException when size is smaller then 1 + */ + public BufferedInputStream(InputStream in, int size) + { + super(in); + if (size <= 0) + throw new IllegalArgumentException(); + buf = new byte[size]; + // initialize pos & count to bufferSize, to prevent refill from + // allocating a new buffer (if the caller starts out by calling mark()). + pos = count = bufferSize = size; + } + + /** + * This method returns the number of bytes that can be read from this + * stream before a read can block. A return of 0 indicates that blocking + * might (or might not) occur on the very next read attempt. + * <p> + * The number of available bytes will be the number of read ahead bytes + * stored in the internal buffer plus the number of available bytes in + * the underlying stream. + * + * @return The number of bytes that can be read before blocking could occur + * + * @exception IOException If an error occurs + */ + public synchronized int available() throws IOException + { + return count - pos + in.available(); + } + + /** + * This method closes the underlying input stream and frees any + * resources associated with it. Sets <code>buf</code> to <code>null</code>. + * + * @exception IOException If an error occurs. + */ + public void close() throws IOException + { + // Free up the array memory. + buf = null; + pos = count = 0; + markpos = -1; + in.close(); + } + + /** + * This method marks a position in the input to which the stream can be + * "reset" by calling the <code>reset()</code> method. The parameter + * <code>readlimit</code> is the number of bytes that can be read from the + * stream after setting the mark before the mark becomes invalid. For + * example, if <code>mark()</code> is called with a read limit of 10, then + * when 11 bytes of data are read from the stream before the + * <code>reset()</code> method is called, then the mark is invalid and the + * stream object instance is not required to remember the mark. + * <p> + * Note that the number of bytes that can be remembered by this method + * can be greater than the size of the internal read buffer. It is also + * not dependent on the subordinate stream supporting mark/reset + * functionality. + * + * @param readlimit The number of bytes that can be read before the mark + * becomes invalid + */ + public synchronized void mark(int readlimit) + { + marklimit = readlimit; + markpos = pos; + } + + /** + * This method returns <code>true</code> to indicate that this class + * supports mark/reset functionality. + * + * @return <code>true</code> to indicate that mark/reset functionality is + * supported + * + */ + public boolean markSupported() + { + return true; + } + + /** + * This method reads an unsigned byte from the input stream and returns it + * as an int in the range of 0-255. This method also will return -1 if + * the end of the stream has been reached. + * <p> + * This method will block until the byte can be read. + * + * @return The byte read or -1 if end of stream + * + * @exception IOException If an error occurs + */ + public synchronized int read() throws IOException + { + if (pos >= count && !refill()) + return -1; // EOF + + return buf[pos++] & 0xFF; + } + + /** + * This method reads bytes from a stream and stores them into a caller + * supplied buffer. It starts storing the data at index <code>off</code> + * into the buffer and attempts to read <code>len</code> bytes. This method + * can return before reading the number of bytes requested, but it will try + * to read the requested number of bytes by repeatedly calling the underlying + * stream as long as available() for this stream continues to return a + * non-zero value (or until the requested number of bytes have been read). + * The actual number of bytes read is returned as an int. A -1 is returned + * to indicate the end of the stream. + * <p> + * This method will block until some data can be read. + * + * @param b The array into which the bytes read should be stored + * @param off The offset into the array to start storing bytes + * @param len The requested number of bytes to read + * + * @return The actual number of bytes read, or -1 if end of stream. + * + * @exception IOException If an error occurs. + * @exception IndexOutOfBoundsException when <code>off</code> or + * <code>len</code> are negative, or when <code>off + len</code> + * is larger then the size of <code>b</code>, + */ + public synchronized int read(byte[] b, int off, int len) throws IOException + { + if (off < 0 || len < 0 || b.length - off < len) + throw new IndexOutOfBoundsException(); + + if (len == 0) + return 0; + + if (pos >= count && !refill()) + return -1; // No bytes were read before EOF. + + int totalBytesRead = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, totalBytesRead); + pos += totalBytesRead; + off += totalBytesRead; + len -= totalBytesRead; + + while (len > 0 && in.available() > 0 && refill()) + { + int remain = Math.min(count - pos, len); + System.arraycopy(buf, pos, b, off, remain); + pos += remain; + off += remain; + len -= remain; + totalBytesRead += remain; + } + + return totalBytesRead; + } + + /** + * This method resets a stream to the point where the <code>mark()</code> + * method was called. Any bytes that were read after the mark point was + * set will be re-read during subsequent reads. + * <p> + * This method will throw an IOException if the number of bytes read from + * the stream since the call to <code>mark()</code> exceeds the mark limit + * passed when establishing the mark. + * + * @exception IOException If <code>mark()</code> was never called or more + * then <code>marklimit</code> bytes were read since the last + * call to <code>mark()</code> + */ + public synchronized void reset() throws IOException + { + if (markpos == -1) + throw new IOException(buf == null ? "Stream closed." : "Invalid mark."); + + pos = markpos; + } + + /** + * This method skips the specified number of bytes in the stream. It + * returns the actual number of bytes skipped, which may be less than the + * requested amount. + * + * @param n The requested number of bytes to skip + * + * @return The actual number of bytes skipped. + * + * @exception IOException If an error occurs + */ + public synchronized long skip(long n) throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + + final long origN = n; + + while (n > 0L) + { + if (pos >= count) + { + if (markpos == -1) + { + // Buffer is empty and no mark is set, skip on the + // underlying stream. + n -= in.skip(n); + break; + } + else if (!refill()) + break; + } + + int numread = (int) Math.min((long) (count - pos), n); + pos += numread; + n -= numread; + } + + return origN - n; + } + + // GCJ LOCAL: package-private for use by InputStreamReader + /** + * Called to refill the buffer (when count is equal to pos). + * + * @return <code>true</code> when at least one additional byte was read + * into <code>buf</code>, <code>false</code> otherwise (at EOF). + */ + boolean refill() throws IOException + { + if (buf == null) + throw new IOException("Stream closed."); + + if (markpos == -1 || count - markpos >= marklimit) + { + markpos = -1; + pos = count = 0; + } + else + { + byte[] newbuf = buf; + if (markpos < bufferSize) + { + newbuf = new byte[count - markpos + bufferSize]; + } + System.arraycopy(buf, markpos, newbuf, 0, count - markpos); + buf = newbuf; + count -= markpos; + pos -= markpos; + markpos = 0; + } + + int numread = in.read(buf, count, bufferSize); + + if (numread <= 0) // EOF + return false; + + count += numread; + return true; + } +} diff --git a/gcc-4.2.1/libjava/java/io/File.java b/gcc-4.2.1/libjava/java/io/File.java new file mode 100644 index 000000000..33776abad --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/File.java @@ -0,0 +1,1416 @@ +/* File.java -- Class representing a file on disk + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import gnu.classpath.Configuration; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Complete to version 1.3. + */ + +/** + * This class represents a file or directory on a local disk. It provides + * facilities for dealing with a variety of systems that use various + * types of path separators ("/" versus "\", for example). It also + * contains method useful for creating and deleting files and directories. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class File implements Serializable, Comparable +{ + private static final long serialVersionUID = 301077366599181567L; + + // QUERY arguments to access function. + private final static int READ = 0; + private final static int WRITE = 1; + private final static int EXISTS = 2; + + // QUERY arguments to stat function. + private final static int DIRECTORY = 0; + private final static int ISFILE = 1; + private final static int ISHIDDEN = 2; + + // QUERY arguments to attr function. + private final static int MODIFIED = 0; + private final static int LENGTH = 1; + + private final native long attr (int query); + // On OSF1 V5.0, `stat' is a macro. It is easiest to use the name + // `_stat' instead. We do the same thing for `_access' just in + // case. + private final native boolean _access (int query); + private final native boolean _stat (int query); + + /** + * This is the path separator string for the current host. This field + * contains the value of the <code>file.separator</code> system property. + * An example separator string would be "/" on the GNU system. + */ + public static final String separator = System.getProperty("file.separator"); + private static final String dupSeparator = separator + separator; + + /** + * This is the first character of the file separator string. On many + * hosts (for example, on the GNU system), this represents the entire + * separator string. The complete separator string is obtained from the + * <code>file.separator</code>system property. + */ + public static final char separatorChar = separator.charAt(0); + + /** + * This is the string that is used to separate the host name from the + * path name in paths than include the host name. It is the value of + * the <code>path.separator</code> system property. + */ + public static final String pathSeparator + = System.getProperty("path.separator"); + + /** + * This is the first character of the string used to separate the host name + * from the path name in paths that include a host. The separator string + * is taken from the <code>path.separator</code> system property. + */ + public static final char pathSeparatorChar = pathSeparator.charAt(0); + + static final String tmpdir = System.getProperty("java.io.tmpdir"); + static int maxPathLen; + static boolean caseSensitive; + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javaio"); + } + + init_native(); + } + + // Native function called at class initialization. This should should + // set the maxPathLen and caseSensitive variables. + private static native void init_native(); + + /** + * This is the path to the file set when the object is created. It + * may be an absolute or relative path name. + */ + private String path; + + // We keep a counter for use by createTempFile. We choose the first + // value randomly to try to avoid clashes with other VMs. + private static long counter = Double.doubleToLongBits (Math.random()); + + /** + * This method tests whether or not the current thread is allowed to + * to read the file pointed to by this object. This will be true if and + * and only if 1) the file exists and 2) the <code>SecurityManager</code> + * (if any) allows access to the file via it's <code>checkRead</code> + * method 3) the file is readable. + * + * @return <code>true</code> if reading is allowed, + * <code>false</code> otherwise + * + * @exception SecurityException If the <code>SecurityManager</code> + * does not allow access to the file + */ + public boolean canRead() + { + checkRead(); + return _access (READ); + } + + /** + * This method test whether or not the current thread is allowed to + * write to this object. This will be true if and only if 1) The + * <code>SecurityManager</code> (if any) allows write access to the + * file and 2) The file exists and 3) The file is writable. To determine + * whether or not a non-existent file can be created, check the parent + * directory for write access. + * + * @return <code>true</code> if writing is allowed, <code>false</code> + * otherwise + * + * @exception SecurityException If the <code>SecurityManager</code> + * does not allow access to the file + */ + public boolean canWrite() + { + checkWrite(); + return _access (WRITE); + } + + private native boolean performCreate() throws IOException; + + /** + * This method creates a new file of zero length with the same name as + * the path of this <code>File</code> object if an only if that file + * does not already exist. + * <p> + * A <code>SecurityManager.checkWrite</code> check is done prior + * to performing this action. + * + * @return <code>true</code> if the file was created, <code>false</code> if + * the file alread existed. + * + * @exception IOException If an I/O error occurs + * @exception SecurityException If the <code>SecurityManager</code> will + * not allow this operation to be performed. + * + * @since 1.2 + */ + public boolean createNewFile() throws IOException + { + checkWrite(); + return performCreate(); + } + + /* + * This native method handles the actual deleting of the file + */ + private native boolean performDelete(); + + /** + * This method deletes the file represented by this object. If this file + * is a directory, it must be empty in order for the delete to succeed. + * + * @return <code>true</code> if the file was deleted, <code>false</code> + * otherwise + * + * @exception SecurityException If deleting of the file is not allowed + */ + public synchronized boolean delete() + { + SecurityManager s = System.getSecurityManager(); + + if (s != null) + s.checkDelete(path); + + return performDelete(); + } + + /** + * This method tests two <code>File</code> objects for equality by + * comparing the path of the specified <code>File</code> against the path + * of this object. The two objects are equal if an only if 1) The + * argument is not null 2) The argument is a <code>File</code> object and + * 3) The path of the <code>File</code>argument is equal to the path + * of this object. + * <p> + * The paths of the files are determined by calling the + * <code>getPath()</code> + * method on each object. + * + * @return <code>true</code> if the two objects are equal, + * <code>false</code> otherwise. + */ + public boolean equals(Object obj) + { + if (! (obj instanceof File)) + return false; + + File other = (File) obj; + + if (caseSensitive) + return path.equals(other.path); + else + return path.equalsIgnoreCase(other.path); + } + + /* + * This method tests whether or not the file represented by the + * object actually exists on the filesystem. + */ + private boolean internalExists() + { + return _access (EXISTS); + } + + /** + * This method tests whether or not the file represented by the object + * actually exists on the filesystem. + * + * @return <code>true</code> if the file exists, <code>false</code>otherwise. + * + * @exception SecurityException If reading of the file is not permitted + */ + public boolean exists() + { + checkRead(); + return internalExists(); + } + + /** + * This method initializes a new <code>File</code> object to represent + * a file with the specified path. + * + * @param name The path name of the file + */ + public File(String name) + { + path = normalizePath (name); + } + + // Remove duplicate and redundant separator characters. + private String normalizePath(String p) + { + // On Windows, convert any '/' to '\'. This appears to be the same logic + // that Sun's Win32 Java performs. + if (separatorChar == '\\') + { + p = p.replace ('/', '\\'); + // We have to special case the "\c:" prefix. + if (p.length() > 2 && p.charAt(0) == '\\' && + ((p.charAt(1) >= 'a' && p.charAt(1) <= 'z') || + (p.charAt(1) >= 'A' && p.charAt(1) <= 'Z')) && + p.charAt(2) == ':') + p = p.substring(1); + } + + int dupIndex = p.indexOf(dupSeparator); + int plen = p.length(); + + // Special case: permit Windows UNC path prefix. + if (dupSeparator.equals("\\\\") && dupIndex == 0) + dupIndex = p.indexOf(dupSeparator, 1); + + if (dupIndex == -1) + { + // Ignore trailing separator (though on Windows "a:\", for + // example, is a valid and minimal path). + if (plen > 1 && p.charAt (plen - 1) == separatorChar) + { + if (! (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':')) + return p.substring (0, plen - 1); + } + else + return p; + } + + StringBuffer newpath = new StringBuffer(plen); + int last = 0; + while (dupIndex != -1) + { + newpath.append(p.substring(last, dupIndex)); + // Ignore the duplicate path characters. + while (p.charAt(dupIndex) == separatorChar) + { + dupIndex++; + if (dupIndex == plen) + return newpath.toString(); + } + newpath.append(separatorChar); + last = dupIndex; + dupIndex = p.indexOf(dupSeparator, last); + } + + // Again, ignore possible trailing separator (except special cases + // like "a:\" on Windows). + int end; + if (plen > 1 && p.charAt (plen - 1) == separatorChar) + { + if (separatorChar == '\\' && plen == 3 && p.charAt (1) == ':') + end = plen; + else + end = plen - 1; + } + else + end = plen; + newpath.append(p.substring(last, end)); + + return newpath.toString(); + } + + /** + * This method initializes a new <code>File</code> object to represent + * a file in the specified named directory. The path name to the file + * will be the directory name plus the separator string plus the file + * name. If the directory path name ends in the separator string, another + * separator string will still be appended. + * + * @param dirPath The path to the directory the file resides in + * @param name The name of the file + */ + public File(String dirPath, String name) + { + if (name == null) + throw new NullPointerException(); + if (dirPath != null) + { + if (dirPath.length() > 0) + { + // Try to be smart about the number of separator characters. + if (dirPath.charAt(dirPath.length() - 1) == separatorChar + || name.length() == 0) + path = normalizePath(dirPath + name); + else + path = normalizePath(dirPath + separatorChar + name); + } + else + { + // If dirPath is empty, use a system dependant + // default prefix. + // Note that the leading separators in name have + // to be chopped off, to prevent them forming + // a UNC prefix on Windows. + if (separatorChar == '\\' /* TODO use ON_WINDOWS */) + { + int skip = 0; + while(name.length() > skip + && (name.charAt(skip) == separatorChar + || name.charAt(skip) == '/')) + { + skip++; + } + name = name.substring(skip); + } + path = normalizePath(separatorChar + name); + } + } + else + path = normalizePath(name); + } + + /** + * This method initializes a new <code>File</code> object to represent + * a file in the specified directory. If the <code>directory</code> + * argument is <code>null</code>, the file is assumed to be in the + * current directory as specified by the <code>user.dir</code> system + * property + * + * @param directory The directory this file resides in + * @param name The name of the file + */ + public File(File directory, String name) + { + this (directory == null ? null : directory.path, name); + } + + /** + * This method initializes a new <code>File</code> object to represent + * a file corresponding to the specified <code>file:</code> protocol URI. + * + * @param uri The uri. + */ + public File(URI uri) + { + if (uri == null) + throw new NullPointerException("uri is null"); + + if (!uri.getScheme().equals("file")) + throw new IllegalArgumentException("invalid uri protocol"); + + String name = uri.getPath(); + if (name == null) + throw new IllegalArgumentException("URI \"" + uri + + "\" is not hierarchical"); + path = normalizePath(name); + } + + /** + * This method returns the path of this file as an absolute path name. + * If the path name is already absolute, then it is returned. Otherwise + * the value returned is the current directory plus the separatory + * string plus the path of the file. The current directory is determined + * from the <code>user.dir</code> system property. + * + * @return The absolute path of this file + */ + public String getAbsolutePath() + { + if (isAbsolute()) + return path; + else if (separatorChar == '\\' + && path.length() > 0 && path.charAt (0) == '\\') + { + // On Windows, even if the path starts with a '\\' it is not + // really absolute until we prefix the drive specifier from + // the current working directory to it. + return System.getProperty ("user.dir").substring (0, 2) + path; + } + else if (separatorChar == '\\' + && path.length() > 1 && path.charAt (1) == ':' + && ((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') + || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z'))) + { + // On Windows, a process has a current working directory for + // each drive and a path like "G:foo\bar" would mean the + // absolute path "G:\wombat\foo\bar" if "\wombat" is the + // working directory on the G drive. + String drvDir = null; + try + { + drvDir = new File (path.substring (0, 2)).getCanonicalPath(); + } + catch (IOException e) + { + drvDir = path.substring (0, 2) + "\\"; + } + + // Note: this would return "C:\\." for the path "C:.", if "\" + // is the working folder on the C drive, but this is + // consistent with what Sun's JRE 1.4.1.01 actually returns! + if (path.length() > 2) + return drvDir + '\\' + path.substring (2, path.length()); + else + return drvDir; + } + else + return System.getProperty ("user.dir") + separatorChar + path; + } + + /** + * This method returns a <code>File</code> object representing the + * absolute path of this object. + * + * @return A <code>File</code> with the absolute path of the object. + * + * @since 1.2 + */ + public File getAbsoluteFile() + { + return new File(getAbsolutePath()); + } + + /** + * This method returns a canonical representation of the pathname of + * this file. The actual form of the canonical representation is + * system-dependent. On the GNU system, conversion to canonical + * form involves the removal of redundant separators, references to + * "." and "..", and symbolic links. + * <p> + * Note that this method, unlike the other methods which return path + * names, can throw an IOException. This is because native method + * might be required in order to resolve the canonical path + * + * @exception IOException If an error occurs + */ + public native String getCanonicalPath() throws IOException; + + /** + * This method returns a <code>File</code> object representing the + * canonical path of this object. + * + * @return A <code>File</code> instance representing the canonical path of + * this object. + * + * @exception IOException If an error occurs. + * + * @since 1.2 + */ + public File getCanonicalFile() throws IOException + { + return new File(getCanonicalPath()); + } + + /** + * This method returns the name of the file. This is everything in the + * complete path of the file after the last instance of the separator + * string. + * + * @return The file name + */ + public String getName() + { + int nameSeqIndex = 0; + + if (separatorChar == '\\' && path.length() > 1) + { + // On Windows, ignore the drive specifier or the leading '\\' + // of a UNC network path, if any (a.k.a. the "prefix"). + if ((path.charAt (0) == '\\' && path.charAt (1) == '\\') + || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') + || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z')) + && path.charAt (1) == ':')) + { + if (path.length() > 2) + nameSeqIndex = 2; + else + return ""; + } + } + + String nameSeq + = (nameSeqIndex > 0 ? path.substring (nameSeqIndex) : path); + + int last = nameSeq.lastIndexOf (separatorChar); + + return nameSeq.substring (last + 1); + } + + /** + * This method returns a <code>String</code> the represents this file's + * parent. <code>null</code> is returned if the file has no parent. The + * parent is determined via a simple operation which removes the + * + * @return The parent directory of this file + */ + public String getParent() + { + String prefix = null; + int nameSeqIndex = 0; + + // The "prefix", if present, is the leading "/" on UNIX and + // either the drive specifier (e.g. "C:") or the leading "\\" + // of a UNC network path on Windows. + if (separatorChar == '/' && path.charAt (0) == '/') + { + prefix = "/"; + nameSeqIndex = 1; + } + else if (separatorChar == '\\' && path.length() > 1) + { + if ((path.charAt (0) == '\\' && path.charAt (1) == '\\') + || (((path.charAt (0) >= 'a' && path.charAt (0) <= 'z') + || (path.charAt (0) >= 'A' && path.charAt (0) <= 'Z')) + && path.charAt (1) == ':')) + { + prefix = path.substring (0, 2); + nameSeqIndex = 2; + } + } + + // According to the JDK docs, the returned parent path is the + // portion of the name sequence before the last separator + // character, if found, prefixed by the prefix, otherwise null. + if (nameSeqIndex < path.length()) + { + String nameSeq = path.substring (nameSeqIndex, path.length()); + int last = nameSeq.lastIndexOf (separatorChar); + if (last == -1) + return prefix; + else if (last == (nameSeq.length() - 1)) + // Note: The path would not have a trailing separator + // except for cases like "C:\" on Windows (see + // normalizePath( )), where Sun's JRE 1.4 returns null. + return null; + else if (last == 0) + last++; + + if (prefix != null) + return prefix + nameSeq.substring (0, last); + else + return nameSeq.substring (0, last); + } + else + // Sun's JRE 1.4 returns null if the prefix is the only + // component of the path - so "/" gives null on UNIX and + // "C:", "\\", etc. return null on Windows. + return null; + } + + /** + * This method returns a <code>File</code> object representing the parent + * file of this one. + * + * @return a <code>File</code> for the parent of this object. + * <code>null</code> + * will be returned if this object does not have a parent. + * + * @since 1.2 + */ + public File getParentFile() + { + String parent = getParent(); + return parent != null ? new File(parent) : null; + } + + /** + * Returns the path name that represents this file. May be a relative + * or an absolute path name + * + * @return The pathname of this file + */ + public String getPath() + { + return path; + } + + /** + * This method returns a hash code representing this file. It is the + * hash code of the path of this file (as returned by <code>getPath()</code>) + * exclusived or-ed with the value 1234321. + * + * @return The hash code for this object + */ + public int hashCode() + { + if (caseSensitive) + return path.hashCode() ^ 1234321; + else + return path.toLowerCase().hashCode() ^ 1234321; + } + + /** + * This method returns true if this object represents an absolute file + * path and false if it does not. The definition of an absolute path varies + * by system. As an example, on GNU systems, a path is absolute if it starts + * with a "/". + * + * @return <code>true</code> if this object represents an absolute + * file name, <code>false</code> otherwise. + */ + public native boolean isAbsolute(); + + /* + * This method tests whether or not the file represented by this + * object is a directory. + */ + private boolean internalIsDirectory() + { + return _stat (DIRECTORY); + } + + /** + * This method tests whether or not the file represented by this object + * is a directory. In order for this method to return <code>true</code>, + * the file represented by this object must exist and be a directory. + * + * @return <code>true</code> if this file is a directory, <code>false</code> + * otherwise + * + * @exception SecurityException If reading of the file is not permitted + */ + public boolean isDirectory() + { + checkRead(); + return internalIsDirectory(); + } + + /** + * This method tests whether or not the file represented by this object + * is a "plain" file. A file is a plain file if and only if it 1) Exists, + * 2) Is not a directory or other type of special file. + * + * @return <code>true</code> if this is a plain file, <code>false</code> + * otherwise + * + * @exception SecurityException If reading of the file is not permitted + */ + public boolean isFile() + { + checkRead(); + return _stat (ISFILE); + } + + /** + * This method tests whether or not this file represents a "hidden" file. + * On GNU systems, a file is hidden if its name begins with a "." + * character. Files with these names are traditionally not shown with + * directory listing tools. + * + * @return <code>true</code> if the file is hidden, <code>false</code> + * otherwise. + * + * @since 1.2 + */ + public boolean isHidden() + { + checkRead(); + return _stat (ISHIDDEN); + } + + /** + * This method returns the last modification time of this file. The + * time value returned is an abstract value that should not be interpreted + * as a specified time value. It is only useful for comparing to other + * such time values returned on the same system. In that case, the larger + * value indicates a more recent modification time. + * <p> + * If the file does not exist, then a value of 0 is returned. + * + * @return The last modification time of the file + * + * @exception SecurityException If reading of the file is not permitted + */ + public long lastModified() + { + checkRead(); + return attr (MODIFIED); + } + + /** + * This method returns the length of the file represented by this object, + * or 0 if the specified file does not exist. + * + * @return The length of the file + * + * @exception SecurityException If reading of the file is not permitted + */ + public long length() + { + checkRead(); + return attr (LENGTH); + } + + /* + * This native function actually produces the list of file in this + * directory + */ + private final native Object[] performList (FilenameFilter filter, + FileFilter fileFilter, + Class result_type); + + /** + * This method returns a array of <code>String</code>'s representing the + * list of files is then directory represented by this object. If this + * object represents a non-directory file or a non-existent file, then + * <code>null</code> is returned. The list of files will not contain + * any names such as "." or ".." which indicate the current or parent + * directory. Also, the names are not guaranteed to be sorted. + * <p> + * In this form of the <code>list()</code> method, a filter is specified + * that allows the caller to control which files are returned in the + * list. The <code>FilenameFilter</code> specified is called for each + * file returned to determine whether or not that file should be included + * in the list. + * <p> + * A <code>SecurityManager</code> check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @param filter An object which will identify files to exclude from + * the directory listing. + * + * @return An array of files in the directory, or <code>null</code> + * if this object does not represent a valid directory. + * + * @exception SecurityException If read access is not allowed to the + * directory by the <code>SecurityManager</code> + */ + public String[] list(FilenameFilter filter) + { + checkRead(); + return (String[]) performList (filter, null, String.class); + } + + /** + * This method returns a array of <code>String</code>'s representing the + * list of files is then directory represented by this object. If this + * object represents a non-directory file or a non-existent file, then + * <code>null</code> is returned. The list of files will not contain + * any names such as "." or ".." which indicate the current or parent + * directory. Also, the names are not guaranteed to be sorted. + * <p> + * A <code>SecurityManager</code> check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of files in the directory, or <code>null</code> if + * this object does not represent a valid directory. + * + * @exception SecurityException If read access is not allowed to the + * directory by the <code>SecurityManager</code> + */ + public String[] list() + { + checkRead(); + return (String[]) performList (null, null, String.class); + } + + /** + * This method returns an array of <code>File</code> objects representing + * all the files in the directory represented by this object. If this + * object does not represent a directory, <code>null</code> is returned. + * Each of the returned <code>File</code> object is constructed with this + * object as its parent. + * <p> + * A <code>SecurityManager</code> check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of <code>File</code> objects for this directory. + * + * @exception SecurityException If the <code>SecurityManager</code> denies + * access to this directory. + * + * @since 1.2 + */ + public File[] listFiles() + { + checkRead(); + return (File[]) performList (null, null, File.class); + } + + /** + * This method returns an array of <code>File</code> objects representing + * all the files in the directory represented by this object. If this + * object does not represent a directory, <code>null</code> is returned. + * Each of the returned <code>File</code> object is constructed with this + * object as its parent. + * <p> + * In this form of the <code>listFiles()</code> method, a filter is specified + * that allows the caller to control which files are returned in the + * list. The <code>FilenameFilter</code> specified is called for each + * file returned to determine whether or not that file should be included + * in the list. + * <p> + * A <code>SecurityManager</code> check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of <code>File</code> objects for this directory. + * + * @exception SecurityException If the <code>SecurityManager</code> denies + * access to this directory. + * + * @since 1.2 + */ + public File[] listFiles(FilenameFilter filter) + { + checkRead(); + return (File[]) performList (filter, null, File.class); + } + + /** + * This method returns an array of <code>File</code> objects representing + * all the files in the directory represented by this object. If this + * object does not represent a directory, <code>null</code> is returned. + * Each of the returned <code>File</code> object is constructed with this + * object as its parent. + * <p> + * In this form of the <code>listFiles()</code> method, a filter is specified + * that allows the caller to control which files are returned in the + * list. The <code>FileFilter</code> specified is called for each + * file returned to determine whether or not that file should be included + * in the list. + * <p> + * A <code>SecurityManager</code> check is made prior to reading the + * directory. If read access to the directory is denied, an exception + * will be thrown. + * + * @return An array of <code>File</code> objects for this directory. + * + * @exception SecurityException If the <code>SecurityManager</code> denies + * access to this directory. + * + * @since 1.2 + */ + public File[] listFiles(FileFilter filter) + { + checkRead(); + return (File[]) performList (null, filter, File.class); + } + + /** + * This method returns a <code>String</code> that is the path name of the + * file as returned by <code>getPath</code>. + * + * @return A <code>String</code> representation of this file + */ + public String toString() + { + return path; + } + + /** + * @return A <code>URI</code> for this object. + */ + public URI toURI() + { + String abspath = getAbsolutePath(); + + if (isDirectory()) + abspath = abspath + separator; + + try + { + return new URI("file", abspath.replace(separatorChar, '/'), null); + } + catch (URISyntaxException use) + { + // Can't happen. + throw new RuntimeException(use); + } + } + + /** + * This method returns a <code>URL</code> with the <code>file:</code> + * protocol that represents this file. The exact form of this URL is + * system dependent. + * + * @return A <code>URL</code> for this object. + * + * @exception MalformedURLException If the URL cannot be created + * successfully. + */ + public URL toURL() throws MalformedURLException + { + // On Win32, Sun's JDK returns URLs of the form "file:/c:/foo/bar.txt", + // while on UNIX, it returns URLs of the form "file:/foo/bar.txt". + if (separatorChar == '\\') + return new URL ("file:/" + getAbsolutePath().replace ('\\', '/') + + (isDirectory() ? "/" : "")); + else + return new URL ("file:" + getAbsolutePath() + + (isDirectory() ? "/" : "")); + } + + /* + * This native method actually creates the directory + */ + private final native boolean performMkdir(); + + /** + * This method creates a directory for the path represented by this object. + * + * @return <code>true</code> if the directory was created, + * <code>false</code> otherwise + * + * @exception SecurityException If write access is not allowed to this file + */ + public boolean mkdir() + { + checkWrite(); + return performMkdir(); + } + + private static boolean mkdirs (File x) + { + if (x.isDirectory()) + return true; + String p = x.getPath(); + String parent = x.getParent(); + if (parent != null) + { + x.path = parent; + if (! mkdirs (x)) + return false; + x.path = p; + } + return x.mkdir(); + } + + /** + * This method creates a directory for the path represented by this file. + * It will also create any intervening parent directories if necessary. + * + * @return <code>true</code> if the directory was created, + * <code>false</code> otherwise + * + * @exception SecurityException If write access is not allowed to this file + */ + public boolean mkdirs() + { + checkWrite(); + if (isDirectory()) + return false; + return mkdirs (new File (path)); + } + + private static synchronized String nextValue() + { + return Long.toString(counter++, Character.MAX_RADIX); + } + + /** + * This method creates a temporary file in the specified directory. If + * the directory name is null, then this method uses the system temporary + * directory. The files created are guaranteed not to currently exist and + * the same file name will never be used twice in the same virtual + * machine instance. + * The system temporary directory is determined by examinging the + * <code>java.io.tmpdir</code> system property. + * <p> + * The <code>prefix</code> parameter is a sequence of at least three + * characters that are used as the start of the generated filename. The + * <code>suffix</code> parameter is a sequence of characters that is used + * to terminate the file name. This parameter may be <code>null</code> + * and if it is, the suffix defaults to ".tmp". + * <p> + * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code> + * method is used to verify that this operation is permitted. + * + * @param prefix The character prefix to use in generating the path name. + * @param suffix The character suffix to use in generating the path name. + * @param directory The directory to create the file in, or + * <code>null</code> for the default temporary directory + * + * @exception IllegalArgumentException If the patterns is not valid + * @exception SecurityException If there is no permission to perform + * this operation + * @exception IOException If an error occurs + * + * @since 1.2 + */ + public static File createTempFile(String prefix, String suffix, + File directory) + throws IOException + { + // Grab the system temp directory if necessary + if (directory == null) + { + String dirname = tmpdir; + if (dirname == null) + throw new IOException("Cannot determine system temporary directory"); + + directory = new File(dirname); + if (!directory.internalExists()) + throw new IOException("System temporary directory " + + directory.getName() + " does not exist."); + if (!directory.internalIsDirectory()) + throw new IOException("System temporary directory " + + directory.getName() + + " is not really a directory."); + } + + // Check if prefix is at least 3 characters long + if (prefix.length() < 3) + throw new IllegalArgumentException("Prefix too short: " + prefix); + + // Set default value of suffix + if (suffix == null) + suffix = ".tmp"; + + // Truncation rules. + // `6' is the number of characters we generate. + if (prefix.length() + 6 + suffix.length() > maxPathLen) + { + int suf_len = 0; + if (suffix.charAt(0) == '.') + suf_len = 4; + suffix = suffix.substring(0, suf_len); + if (prefix.length() + 6 + suf_len > maxPathLen) + prefix = prefix.substring(0, maxPathLen - 6 - suf_len); + } + + File f; + + // How many times should we try? We choose 100. + for (int i = 0; i < 100; ++i) + { + // This is ugly. + String t = "ZZZZZZ" + nextValue(); + String l = prefix + t.substring(t.length() - 6) + suffix; + try + { + f = new File(directory, l); + if (f.createNewFile()) + return f; + } + catch (IOException ignored) + { + } + } + + throw new IOException ("cannot create temporary file"); + } + + /* + * This native method sets the permissions to make the file read only. + */ + private native boolean performSetReadOnly(); + + /** + * This method sets the file represented by this object to be read only. + * A read only file or directory cannot be modified. Please note that + * GNU systems allow read only files to be deleted if the directory it + * is contained in is writable. + * + * @return <code>true</code> if the operation succeeded, <code>false</code> + * otherwise. + * + * @exception SecurityException If the <code>SecurityManager</code> does + * not allow this operation. + * + * @since 1.2 + */ + public boolean setReadOnly() + { + // Do a security check before trying to do anything else. + checkWrite(); + return performSetReadOnly(); + } + + private static native File[] performListRoots(); + + /** + * This method returns an array of filesystem roots. Some operating systems + * have volume oriented filesystem. This method provides a mechanism for + * determining which volumes exist. GNU systems use a single hierarchical + * filesystem, so will have only one "/" filesystem root. + * + * @return An array of <code>File</code> objects for each filesystem root + * available. + * + * @since 1.2 + */ + public static File[] listRoots() + { + File[] roots = performListRoots(); + + SecurityManager s = System.getSecurityManager(); + if (s != null) + { + // Only return roots to which the security manager permits read access. + int count = roots.length; + for (int i = 0; i < roots.length; i++) + { + try + { + s.checkRead (roots[i].path); + } + catch (SecurityException sx) + { + roots[i] = null; + count--; + } + } + if (count != roots.length) + { + File[] newRoots = new File[count]; + int k = 0; + for (int i=0; i < roots.length; i++) + { + if (roots[i] != null) + newRoots[k++] = roots[i]; + } + roots = newRoots; + } + } + return roots; + } + + /** + * This method creates a temporary file in the system temporary directory. + * The files created are guaranteed not to currently exist and the same file + * name will never be used twice in the same virtual machine instance. The + * system temporary directory is determined by examinging the + * <code>java.io.tmpdir</code> system property. + * <p> + * The <code>prefix</code> parameter is a sequence of at least three + * characters that are used as the start of the generated filename. The + * <code>suffix</code> parameter is a sequence of characters that is used + * to terminate the file name. This parameter may be <code>null</code> + * and if it is, the suffix defaults to ".tmp". + * <p> + * If a <code>SecurityManager</code> exists, then its <code>checkWrite</code> + * method is used to verify that this operation is permitted. + * <p> + * This method is identical to calling + * <code>createTempFile(prefix, suffix, null)</code>. + * + * @param prefix The character prefix to use in generating the path name. + * @param suffix The character suffix to use in generating the path name. + * + * @exception IllegalArgumentException If the prefix or suffix are not valid. + * @exception SecurityException If there is no permission to perform + * this operation + * @exception IOException If an error occurs + */ + public static File createTempFile(String prefix, String suffix) + throws IOException + { + return createTempFile(prefix, suffix, null); + } + + /** + * This method compares the specified <code>File</code> to this one + * to test for equality. It does this by comparing the canonical path names + * of the files. + * <p> + * The canonical paths of the files are determined by calling the + * <code>getCanonicalPath</code> method on each object. + * <p> + * This method returns a 0 if the specified <code>Object</code> is equal + * to this one, a negative value if it is less than this one + * a positive value if it is greater than this one. + * + * @return An integer as described above + * + * @since 1.2 + */ + public int compareTo(File other) + { + if (caseSensitive) + return path.compareTo (other.path); + else + return path.compareToIgnoreCase (other.path); + } + + /** + * This method compares the specified <code>Object</code> to this one + * to test for equality. It does this by comparing the canonical path names + * of the files. This method is identical to <code>compareTo(File)</code> + * except that if the <code>Object</code> passed to it is not a + * <code>File</code>, it throws a <code>ClassCastException</code> + * <p> + * The canonical paths of the files are determined by calling the + * <code>getCanonicalPath</code> method on each object. + * <p> + * This method returns a 0 if the specified <code>Object</code> is equal + * to this one, a negative value if it is less than this one + * a positive value if it is greater than this one. + * + * @return An integer as described above + * + * @exception ClassCastException If the passed <code>Object</code> is + * not a <code>File</code> + * + * @since 1.2 + */ + public int compareTo(Object obj) + { + return compareTo((File) obj); + } + + /* + * This native method actually performs the rename. + */ + private native boolean performRenameTo (File dest); + + /** + * This method renames the file represented by this object to the path + * of the file represented by the argument <code>File</code>. + * + * @param dest The <code>File</code> object representing the target name + * + * @return <code>true</code> if the rename succeeds, <code>false</code> + * otherwise. + * + * @exception SecurityException If write access is not allowed to the + * file by the <code>SecurityMananger</code>. + */ + public synchronized boolean renameTo(File dest) + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + { + s.checkWrite (getPath()); + s.checkWrite (dest.getPath()); + } + return performRenameTo (dest); + } + + /* + * This method does the actual setting of the modification time. + */ + private native boolean performSetLastModified(long time); + + /** + * This method sets the modification time on the file to the specified + * value. This is specified as the number of seconds since midnight + * on January 1, 1970 GMT. + * + * @param time The desired modification time. + * + * @return <code>true</code> if the operation succeeded, <code>false</code> + * otherwise. + * + * @exception IllegalArgumentException If the specified time is negative. + * @exception SecurityException If the <code>SecurityManager</code> will + * not allow this operation. + * + * @since 1.2 + */ + public boolean setLastModified(long time) + { + if (time < 0) + throw new IllegalArgumentException("Negative modification time: " + time); + + checkWrite(); + return performSetLastModified(time); + } + + private void checkWrite() + { + // Check the SecurityManager + SecurityManager s = System.getSecurityManager(); + + if (s != null) + s.checkWrite(path); + } + + private void checkRead() + { + // Check the SecurityManager + SecurityManager s = System.getSecurityManager(); + + if (s != null) + s.checkRead(path); + } + + /** + * Calling this method requests that the file represented by this object + * be deleted when the virtual machine exits. Note that this request cannot + * be cancelled. Also, it will only be carried out if the virtual machine + * exits normally. + * + * @exception SecurityException If deleting of the file is not allowed + * + * @since 1.2 + */ + // FIXME: This should use the ShutdownHook API once we implement that. + public void deleteOnExit() + { + // Check the SecurityManager + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkDelete (getPath()); + + DeleteFileHelper.add(this); + } + + private void writeObject(ObjectOutputStream oos) throws IOException + { + oos.defaultWriteObject(); + oos.writeChar(separatorChar); + } + + private void readObject(ObjectInputStream ois) + throws ClassNotFoundException, IOException + { + ois.defaultReadObject(); + + // If the file was from an OS with a different dir separator, + // fixup the path to use the separator on this OS. + char oldSeparatorChar = ois.readChar(); + + if (oldSeparatorChar != separatorChar) + path = path.replace(oldSeparatorChar, separatorChar); + } + +} // class File + diff --git a/gcc-4.2.1/libjava/java/io/InputStreamReader.java b/gcc-4.2.1/libjava/java/io/InputStreamReader.java new file mode 100644 index 000000000..91568c5cc --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/InputStreamReader.java @@ -0,0 +1,332 @@ +/* InputStreamReader.java -- Reader than transforms bytes to chars + Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import gnu.gcj.convert.*; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; + +/** + * This class reads characters from a byte input stream. The characters + * read are converted from bytes in the underlying stream by a + * decoding layer. The decoding layer transforms bytes to chars according + * to an encoding standard. There are many available encodings to choose + * from. The desired encoding can either be specified by name, or if no + * encoding is selected, the system default encoding will be used. The + * system default encoding name is determined from the system property + * <code>file.encoding</code>. The only encodings that are guaranteed to + * be availalbe are "8859_1" (the Latin-1 character set) and "UTF8". + * Unforunately, Java does not provide a mechanism for listing the + * ecodings that are supported in a given implementation. + * <p> + * Here is a list of standard encoding names that may be available: + * <p> + * <ul> + * <li>8859_1 (ISO-8859-1/Latin-1)</li> + * <li>8859_2 (ISO-8859-2/Latin-2)</li> + * <li>8859_3 (ISO-8859-3/Latin-3)</li> + * <li>8859_4 (ISO-8859-4/Latin-4)</li> + * <li>8859_5 (ISO-8859-5/Latin-5)</li> + * <li>8859_6 (ISO-8859-6/Latin-6)</li> + * <li>8859_7 (ISO-8859-7/Latin-7)</li> + * <li>8859_8 (ISO-8859-8/Latin-8)</li> + * <li>8859_9 (ISO-8859-9/Latin-9)</li> + * <li>ASCII (7-bit ASCII)</li> + * <li>UTF8 (UCS Transformation Format-8)</li> + * <li>More later</li> + * </ul> + * <p> + * It is recommended that applications do not use + * <code>InputStreamReader</code>'s + * directly. Rather, for efficiency purposes, an object of this class + * should be wrapped by a <code>BufferedReader</code>. + * <p> + * Due to a deficiency the Java class library design, there is no standard + * way for an application to install its own byte-character encoding. + * + * @see BufferedReader + * @see InputStream + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + * @date April 22, 1998. + */ +public class InputStreamReader extends Reader +{ + BufferedInputStream in; + + // Buffer of chars read from in and converted but not consumed. + char[] work; + // Next available character (in work buffer) to read. + int wpos; + // Last available character (in work buffer) to read. + int wcount; + + /* + * This is the byte-character decoder class that does the reading and + * translation of bytes from the underlying stream. + */ + BytesToUnicode converter; + + /** + * This method initializes a new instance of <code>InputStreamReader</code> + * to read from the specified stream using the default encoding. + * + * @param in The <code>InputStream</code> to read from + */ + public InputStreamReader(InputStream in) + { + this(in, BytesToUnicode.getDefaultDecoder()); + } + + /** + * This method initializes a new instance of <code>InputStreamReader</code> + * to read from the specified stream using a caller supplied character + * encoding scheme. Note that due to a deficiency in the Java language + * design, there is no way to determine which encodings are supported. + * + * @param in The <code>InputStream</code> to read from + * @param encoding_name The name of the encoding scheme to use + * + * @exception UnsupportedEncodingException If the encoding scheme + * requested is not available. + */ + public InputStreamReader(InputStream in, String encoding_name) + throws UnsupportedEncodingException + { + this(in, BytesToUnicode.getDecoder(encoding_name)); + } + + /** + * Creates an InputStreamReader that uses a decoder of the given + * charset to decode the bytes in the InputStream into + * characters. + */ + public InputStreamReader(InputStream in, Charset charset) + { + this(in, new BytesToCharsetAdaptor(charset)); + } + + /** + * Creates an InputStreamReader that uses the given charset decoder + * to decode the bytes in the InputStream into characters. + */ + public InputStreamReader(InputStream in, CharsetDecoder decoder) + { + this(in, new BytesToCharsetAdaptor(decoder)); + } + + private InputStreamReader(InputStream in, BytesToUnicode decoder) + { + // FIXME: someone could pass in a BufferedInputStream whose buffer + // is smaller than the longest encoded character for this + // encoding. We will probably go into an infinite loop in this + // case. We probably ought to just have our own byte buffering + // here. + this.in = in instanceof BufferedInputStream + ? (BufferedInputStream) in + : new BufferedInputStream(in); + /* Don't need to call super(in) here as long as the lock gets set. */ + this.lock = in; + converter = decoder; + converter.setInput(this.in.buf, 0, 0); + } + + /** + * This method closes this stream, as well as the underlying + * <code>InputStream</code>. + * + * @exception IOException If an error occurs + */ + public void close() throws IOException + { + synchronized (lock) + { + if (in != null) + in.close(); + in = null; + work = null; + wpos = wcount = 0; + } + } + + /** + * This method returns the name of the encoding that is currently in use + * by this object. If the stream has been closed, this method is allowed + * to return <code>null</code>. + * + * @return The current encoding name + */ + public String getEncoding() + { + return in != null ? converter.getName() : null; + } + + /** + * This method checks to see if the stream is read to be read. It + * will return <code>true</code> if is, or <code>false</code> if it is not. + * If the stream is not ready to be read, it could (although is not required + * to) block on the next read attempt. + * + * @return <code>true</code> if the stream is ready to be read, + * <code>false</code> otherwise + * + * @exception IOException If an error occurs + */ + public boolean ready() throws IOException + { + synchronized (lock) + { + if (in == null) + throw new IOException("Stream closed"); + + if (wpos < wcount) + return true; + + // According to the spec, an InputStreamReader is ready if its + // input buffer is not empty (above), or if bytes are + // available on the underlying byte stream. + return in.available () > 0; + } + } + + /** + * This method reads up to <code>length</code> characters from the stream into + * the specified array starting at index <code>offset</code> into the + * array. + * + * @param buf The character array to recieve the data read + * @param offset The offset into the array to start storing characters + * @param length The requested number of characters to read. + * + * @return The actual number of characters read, or -1 if end of stream. + * + * @exception IOException If an error occurs + */ + public int read (char[] buf, int offset, int length) throws IOException + { + synchronized (lock) + { + if (in == null) + throw new IOException("Stream closed"); + + if (length == 0) + return 0; + + int wavail = wcount - wpos; + if (wavail <= 0) + { + // Nothing waiting, so refill their buffer. + return refill(buf, offset, length); + } + + if (length > wavail) + length = wavail; + System.arraycopy(work, wpos, buf, offset, length); + wpos += length; + return length; + } + } + + /** + * This method reads a single character of data from the stream. + * + * @return The char read, as an int, or -1 if end of stream. + * + * @exception IOException If an error occurs + */ + public int read() throws IOException + { + synchronized (lock) + { + if (in == null) + throw new IOException("Stream closed"); + + int wavail = wcount - wpos; + if (wavail <= 0) + { + // Nothing waiting, so refill our internal buffer. + wpos = wcount = 0; + if (work == null) + work = new char[100]; + int count = refill(work, 0, work.length); + if (count == -1) + return -1; + wcount += count; + } + + return work[wpos++]; + } + } + + // Read more bytes and convert them into the specified buffer. + // Returns the number of converted characters or -1 on EOF. + private int refill(char[] buf, int offset, int length) throws IOException + { + for (;;) + { + // We have knowledge of the internals of BufferedInputStream + // here. Eww. + // BufferedInputStream.refill() can only be called when + // `pos>=count'. + boolean r = in.pos < in.count || in.refill (); + if (! r) + return -1; + converter.setInput(in.buf, in.pos, in.count); + int count = converter.read(buf, offset, length); + + // We might have bytes but not have made any progress. In + // this case we try to refill. If refilling fails, we assume + // we have a malformed character at the end of the stream. + if (count == 0 && converter.inpos == in.pos) + { + in.mark(in.count); + if (! in.refill ()) + throw new CharConversionException (); + in.reset(); + } + else + { + in.skip(converter.inpos - in.pos); + if (count > 0) + return count; + } + } + } +} diff --git a/gcc-4.2.1/libjava/java/io/ObjectInputStream.java b/gcc-4.2.1/libjava/java/io/ObjectInputStream.java new file mode 100644 index 000000000..54661a9bc --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/ObjectInputStream.java @@ -0,0 +1,1979 @@ +/* ObjectInputStream.java -- Class used to read serialized objects + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import gnu.classpath.Configuration; +import gnu.java.io.ObjectIdentityWrapper; + +import java.lang.reflect.Array; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.Proxy; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.Vector; + +public class ObjectInputStream extends InputStream + implements ObjectInput, ObjectStreamConstants +{ + /** + * Creates a new <code>ObjectInputStream</code> that will do all of + * its reading from <code>in</code>. This method also checks + * the stream by reading the header information (stream magic number + * and stream version). + * + * @exception IOException Reading stream header from underlying + * stream cannot be completed. + * + * @exception StreamCorruptedException An invalid stream magic + * number or stream version was read from the stream. + * + * @see #readStreamHeader() + */ + public ObjectInputStream(InputStream in) + throws IOException, StreamCorruptedException + { + if (Configuration.DEBUG) + { + String val = System.getProperty("gcj.dumpobjects"); + if (dump == false && val != null && !val.equals("")) + { + dump = true; + System.out.println ("Serialization debugging enabled"); + } + else if (dump == true && (val == null || val.equals(""))) + { + dump = false; + System.out.println ("Serialization debugging disabled"); + } + } + + this.resolveEnabled = false; + this.isDeserializing = false; + this.blockDataPosition = 0; + this.blockDataBytes = 0; + this.blockData = new byte[BUFFER_SIZE]; + this.blockDataInput = new DataInputStream(this); + this.realInputStream = new DataInputStream(in); + this.nextOID = baseWireHandle; + this.objectLookupTable = new Hashtable(); + this.validators = new Vector(); + this.classLookupTable = new Hashtable(); + setBlockDataMode(true); + readStreamHeader(); + } + + + /** + * Returns the next deserialized object read from the underlying stream. + * + * This method can be overriden by a class by implementing + * <code>private void readObject (ObjectInputStream)</code>. + * + * If an exception is thrown from this method, the stream is left in + * an undefined state. This method can also throw Errors and + * RuntimeExceptions if caused by existing readResolve() user code. + * + * @return The object read from the underlying stream. + * + * @exception ClassNotFoundException The class that an object being + * read in belongs to cannot be found. + * + * @exception IOException Exception from underlying + * <code>InputStream</code>. + */ + public final Object readObject() throws ClassNotFoundException, IOException + { + if (this.useSubclassMethod) + return readObjectOverride(); + + boolean was_deserializing; + + Object ret_val; + was_deserializing = this.isDeserializing; + + boolean is_consumed = false; + boolean old_mode = setBlockDataMode(false); + + this.isDeserializing = true; + + byte marker = this.realInputStream.readByte(); + + depth += 2; + + if(dump) dumpElement("MARKER: 0x" + Integer.toHexString(marker) + " "); + + try + { + switch (marker) + { + case TC_ENDBLOCKDATA: + { + ret_val = null; + is_consumed = true; + break; + } + + case TC_BLOCKDATA: + case TC_BLOCKDATALONG: + { + if (marker == TC_BLOCKDATALONG) + { if(dump) dumpElementln("BLOCKDATALONG"); } + else + { if(dump) dumpElementln("BLOCKDATA"); } + readNextBlock(marker); + throw new StreamCorruptedException("Unexpected blockData"); + } + + case TC_NULL: + { + if(dump) dumpElementln("NULL"); + ret_val = null; + break; + } + + case TC_REFERENCE: + { + if(dump) dumpElement("REFERENCE "); + Integer oid = new Integer(this.realInputStream.readInt()); + if(dump) dumpElementln(Integer.toHexString(oid.intValue())); + ret_val = ((ObjectIdentityWrapper) + this.objectLookupTable.get(oid)).object; + break; + } + + case TC_CLASS: + { + if(dump) dumpElementln("CLASS"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class clazz = osc.forClass(); + assignNewHandle(clazz); + ret_val = clazz; + break; + } + + case TC_PROXYCLASSDESC: + { + if(dump) dumpElementln("PROXYCLASS"); + int n_intf = this.realInputStream.readInt(); + String[] intfs = new String[n_intf]; + for (int i = 0; i < n_intf; i++) + { + intfs[i] = this.realInputStream.readUTF(); + } + + boolean oldmode = setBlockDataMode(true); + Class cl = resolveProxyClass(intfs); + setBlockDataMode(oldmode); + + ObjectStreamClass osc = lookupClass(cl); + if (osc.firstNonSerializableParentConstructor == null) + { + osc.realClassIsSerializable = true; + osc.fields = osc.fieldMapping = new ObjectStreamField[0]; + try + { + osc.firstNonSerializableParentConstructor = + Object.class.getConstructor(new Class[0]); + } + catch (NoSuchMethodException x) + { + throw (InternalError) + new InternalError("Object ctor missing").initCause(x); + } + } + assignNewHandle(osc); + + if (!is_consumed) + { + byte b = this.realInputStream.readByte(); + if (b != TC_ENDBLOCKDATA) + throw new IOException("Data annotated to class was not consumed." + b); + } + else + is_consumed = false; + ObjectStreamClass superosc = (ObjectStreamClass)readObject(); + osc.setSuperclass(superosc); + ret_val = osc; + break; + } + + case TC_CLASSDESC: + { + ObjectStreamClass osc = readClassDescriptor(); + + if (!is_consumed) + { + byte b = this.realInputStream.readByte(); + if (b != TC_ENDBLOCKDATA) + throw new IOException("Data annotated to class was not consumed." + b); + } + else + is_consumed = false; + + osc.setSuperclass ((ObjectStreamClass)readObject()); + ret_val = osc; + break; + } + + case TC_STRING: + case TC_LONGSTRING: + { + if(dump) dumpElement("STRING="); + String s = this.realInputStream.readUTF(); + if(dump) dumpElementln(s); + ret_val = processResolution(null, s, assignNewHandle(s)); + break; + } + + case TC_ARRAY: + { + if(dump) dumpElementln("ARRAY"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class componentType = osc.forClass().getComponentType(); + if(dump) dumpElement("ARRAY LENGTH="); + int length = this.realInputStream.readInt(); + if(dump) dumpElementln (length + "; COMPONENT TYPE=" + componentType); + Object array = Array.newInstance(componentType, length); + int handle = assignNewHandle(array); + readArrayElements(array, componentType); + if(dump) + for (int i = 0, len = Array.getLength(array); i < len; i++) + dumpElementln(" ELEMENT[" + i + "]=" + Array.get(array, i)); + ret_val = processResolution(null, array, handle); + break; + } + + case TC_OBJECT: + { + if(dump) dumpElementln("OBJECT"); + ObjectStreamClass osc = (ObjectStreamClass)readObject(); + Class clazz = osc.forClass(); + + if (!osc.realClassIsSerializable) + throw new NotSerializableException + (clazz + " is not Serializable, and thus cannot be deserialized."); + + if (osc.realClassIsExternalizable) + { + Externalizable obj = osc.newInstance(); + + int handle = assignNewHandle(obj); + + boolean read_from_blocks = ((osc.getFlags() & SC_BLOCK_DATA) != 0); + + boolean oldmode = this.readDataFromBlock; + if (read_from_blocks) + setBlockDataMode(true); + + obj.readExternal(this); + + if (read_from_blocks) + { + setBlockDataMode(oldmode); + if (!oldmode) + if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) + throw new IOException("No end of block data seen for class with readExternal (ObjectInputStream) method."); + } + + ret_val = processResolution(osc, obj, handle); + break; + } // end if (osc.realClassIsExternalizable) + + Object obj = newObject(clazz, osc.firstNonSerializableParentConstructor); + + int handle = assignNewHandle(obj); + Object prevObject = this.currentObject; + ObjectStreamClass prevObjectStreamClass = this.currentObjectStreamClass; + + this.currentObject = obj; + ObjectStreamClass[] hierarchy = + inputGetObjectStreamClasses(clazz); + + for (int i = 0; i < hierarchy.length; i++) + { + this.currentObjectStreamClass = hierarchy[i]; + + if(dump) dumpElementln("Reading fields of " + this.currentObjectStreamClass.getName ()); + + // XXX: should initialize fields in classes in the hierarchy + // that aren't in the stream + // should skip over classes in the stream that aren't in the + // real classes hierarchy + + Method readObjectMethod = this.currentObjectStreamClass.readObjectMethod; + if (readObjectMethod != null) + { + fieldsAlreadyRead = false; + boolean oldmode = setBlockDataMode(true); + callReadMethod(readObjectMethod, this.currentObjectStreamClass.forClass(), obj); + setBlockDataMode(oldmode); + } + else + { + readFields(obj, currentObjectStreamClass); + } + + if (this.currentObjectStreamClass.hasWriteMethod()) + { + if(dump) dumpElement("ENDBLOCKDATA? "); + try + { + // FIXME: XXX: This try block is to + // catch EOF which is thrown for some + // objects. That indicates a bug in + // the logic. + + if (this.realInputStream.readByte() != TC_ENDBLOCKDATA) + throw new IOException + ("No end of block data seen for class with readObject (ObjectInputStream) method."); + if(dump) dumpElementln("yes"); + } +// catch (EOFException e) +// { +// if(dump) dumpElementln("no, got EOFException"); +// } + catch (IOException e) + { + if(dump) dumpElementln("no, got IOException"); + } + } + } + + this.currentObject = prevObject; + this.currentObjectStreamClass = prevObjectStreamClass; + ret_val = processResolution(osc, obj, handle); + + break; + } + + case TC_RESET: + if(dump) dumpElementln("RESET"); + clearHandles(); + ret_val = readObject(); + break; + + case TC_EXCEPTION: + { + if(dump) dumpElement("EXCEPTION="); + Exception e = (Exception)readObject(); + if(dump) dumpElementln(e.toString()); + clearHandles(); + throw new WriteAbortedException("Exception thrown during writing of stream", e); + } + + default: + throw new IOException("Unknown marker on stream: " + marker); + } + } + finally + { + setBlockDataMode(old_mode); + + this.isDeserializing = was_deserializing; + + depth -= 2; + + if (! was_deserializing) + { + if (validators.size() > 0) + invokeValidators(); + } + } + + return ret_val; + } + + /** + * This method makes a partial check of types for the fields + * contained given in arguments. It checks primitive types of + * fields1 against non primitive types of fields2. This method + * assumes the two lists has already been sorted according to + * the Java specification. + * + * @param name Name of the class owning the given fields. + * @param fields1 First list to check. + * @param fields2 Second list to check. + * @throws InvalidClassException if a field in fields1, which has a primitive type, is a present + * in the non primitive part in fields2. + */ + private void checkTypeConsistency(String name, ObjectStreamField[] fields1, ObjectStreamField[] fields2) + throws InvalidClassException + { + int nonPrimitive = 0; + + for (nonPrimitive = 0; + nonPrimitive < fields1.length + && fields1[nonPrimitive].isPrimitive(); nonPrimitive++) + { + } + + if (nonPrimitive == fields1.length) + return; + + int i = 0; + ObjectStreamField f1; + ObjectStreamField f2; + + while (i < fields2.length + && nonPrimitive < fields1.length) + { + f1 = fields1[nonPrimitive]; + f2 = fields2[i]; + + if (!f2.isPrimitive()) + break; + + int compVal = f1.getName().compareTo (f2.getName()); + + if (compVal < 0) + { + nonPrimitive++; + } + else if (compVal > 0) + { + i++; + } + else + { + throw new InvalidClassException + ("invalid field type for " + f2.getName() + + " in class " + name); + } + } + } + + /** + * This method reads a class descriptor from the real input stream + * and use these data to create a new instance of ObjectStreamClass. + * Fields are sorted and ordered for the real read which occurs for + * each instance of the described class. Be aware that if you call that + * method you must ensure that the stream is synchronized, in the other + * case it may be completely desynchronized. + * + * @return A new instance of ObjectStreamClass containing the freshly + * created descriptor. + * @throws ClassNotFoundException if the required class to build the + * descriptor has not been found in the system. + * @throws IOException An input/output error occured. + * @throws InvalidClassException If there was a compatibility problem + * between the class present in the system and the serialized class. + */ + protected ObjectStreamClass readClassDescriptor() + throws ClassNotFoundException, IOException + { + if(dump) dumpElement("CLASSDESC NAME="); + String name = this.realInputStream.readUTF(); + if(dump) dumpElement(name + "; UID="); + long uid = this.realInputStream.readLong (); + if(dump) dumpElement(Long.toHexString(uid) + "; FLAGS="); + byte flags = this.realInputStream.readByte (); + if(dump) dumpElement(Integer.toHexString(flags) + "; FIELD COUNT="); + short field_count = this.realInputStream.readShort(); + if(dump) dumpElementln(Short.toString(field_count)); + ObjectStreamField[] fields = new ObjectStreamField[field_count]; + ObjectStreamClass osc = new ObjectStreamClass(name, uid, + flags, fields); + assignNewHandle(osc); + + if (callersClassLoader == null) + callersClassLoader = currentLoader(); + + for (int i = 0; i < field_count; i++) + { + if(dump) dumpElement(" TYPE CODE="); + char type_code = (char)this.realInputStream.readByte(); + if(dump) dumpElement(type_code + "; FIELD NAME="); + String field_name = this.realInputStream.readUTF(); + if(dump) dumpElementln(field_name); + String class_name; + + // If the type code is an array or an object we must + // decode a String here. In the other case we convert + // the type code and pass it to ObjectStreamField. + // Type codes are decoded by gnu.java.lang.reflect.TypeSignature. + if (type_code == 'L' || type_code == '[') + class_name = (String)readObject(); + else + class_name = String.valueOf(type_code); + + fields[i] = + new ObjectStreamField(field_name, class_name, callersClassLoader); + } + + /* Now that fields have been read we may resolve the class + * (and read annotation if needed). */ + Class clazz; + try + { + clazz = resolveClass(osc); + } + catch (ClassNotFoundException cnfe) + { + // Maybe it was an primitive class? + if (name.equals("void")) + clazz = Void.TYPE; + else if (name.equals("boolean")) + clazz = Boolean.TYPE; + else if (name.equals("byte")) + clazz = Byte.TYPE; + else if (name.equals("short")) + clazz = Short.TYPE; + else if (name.equals("char")) + clazz = Character.TYPE; + else if (name.equals("int")) + clazz = Integer.TYPE; + else if (name.equals("long")) + clazz = Long.TYPE; + else if (name.equals("float")) + clazz = Float.TYPE; + else if (name.equals("double")) + clazz = Double.TYPE; + else + throw cnfe; + } + + boolean oldmode = setBlockDataMode(true); + osc.setClass(clazz, lookupClass(clazz.getSuperclass())); + classLookupTable.put(clazz, osc); + setBlockDataMode(oldmode); + + // find the first non-serializable, non-abstract + // class in clazz's inheritance hierarchy + Class first_nonserial = clazz.getSuperclass(); + // Maybe it is a primitive class, those don't have a super class, + // or Object itself. Otherwise we can keep getting the superclass + // till we hit the Object class, or some other non-serializable class. + + if (first_nonserial == null) + first_nonserial = clazz; + else + while (Serializable.class.isAssignableFrom(first_nonserial) + || Modifier.isAbstract(first_nonserial.getModifiers())) + first_nonserial = first_nonserial.getSuperclass(); + + final Class local_constructor_class = first_nonserial; + + osc.firstNonSerializableParentConstructor = + (Constructor)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Constructor c = local_constructor_class. + getDeclaredConstructor(new Class[0]); + if (Modifier.isPrivate(c.getModifiers())) + return null; + return c; + } + catch (NoSuchMethodException e) + { + // error will be reported later, in newObject() + return null; + } + } + }); + + osc.realClassIsSerializable = Serializable.class.isAssignableFrom(clazz); + osc.realClassIsExternalizable = Externalizable.class.isAssignableFrom(clazz); + + ObjectStreamField[] stream_fields = osc.fields; + ObjectStreamField[] real_fields = ObjectStreamClass.lookupForClassObject(clazz).fields; + ObjectStreamField[] fieldmapping = new ObjectStreamField[2 * Math.max(stream_fields.length, real_fields.length)]; + + int stream_idx = 0; + int real_idx = 0; + int map_idx = 0; + + /* + * Check that there is no type inconsistencies between the lists. + * A special checking must be done for the two groups: primitive types and + * not primitive types. + */ + checkTypeConsistency(name, real_fields, stream_fields); + checkTypeConsistency(name, stream_fields, real_fields); + + + while (stream_idx < stream_fields.length + || real_idx < real_fields.length) + { + ObjectStreamField stream_field = null; + ObjectStreamField real_field = null; + + if (stream_idx == stream_fields.length) + { + real_field = real_fields[real_idx++]; + } + else if (real_idx == real_fields.length) + { + stream_field = stream_fields[stream_idx++]; + } + else + { + int comp_val = + real_fields[real_idx].compareTo (stream_fields[stream_idx]); + + if (comp_val < 0) + { + real_field = real_fields[real_idx++]; + } + else if (comp_val > 0) + { + stream_field = stream_fields[stream_idx++]; + } + else + { + stream_field = stream_fields[stream_idx++]; + real_field = real_fields[real_idx++]; + if (stream_field.getType() != real_field.getType()) + throw new InvalidClassException + ("invalid field type for " + real_field.getName() + + " in class " + name); + } + } + + /* If some of stream_fields does not correspond to any of real_fields, + * or the opposite, then fieldmapping will go short. + */ + if (map_idx == fieldmapping.length) + { + ObjectStreamField[] newfieldmapping = + new ObjectStreamField[fieldmapping.length + 2]; + System.arraycopy(fieldmapping, 0, + newfieldmapping, 0, fieldmapping.length); + fieldmapping = newfieldmapping; + } + fieldmapping[map_idx++] = stream_field; + fieldmapping[map_idx++] = real_field; + } + osc.fieldMapping = fieldmapping; + + return osc; + } + + /** + * Reads the current objects non-transient, non-static fields from + * the current class from the underlying output stream. + * + * This method is intended to be called from within a object's + * <code>private void readObject (ObjectInputStream)</code> + * method. + * + * @exception ClassNotFoundException The class that an object being + * read in belongs to cannot be found. + * + * @exception NotActiveException This method was called from a + * context other than from the current object's and current class's + * <code>private void readObject (ObjectInputStream)</code> + * method. + * + * @exception IOException Exception from underlying + * <code>OutputStream</code>. + */ + public void defaultReadObject() + throws ClassNotFoundException, IOException, NotActiveException + { + if (this.currentObject == null || this.currentObjectStreamClass == null) + throw new NotActiveException("defaultReadObject called by non-active" + + " class and/or object"); + + if (fieldsAlreadyRead) + throw new NotActiveException("defaultReadObject called but fields " + + "already read from stream (by " + + "defaultReadObject or readFields)"); + + boolean oldmode = setBlockDataMode(false); + readFields(this.currentObject, this.currentObjectStreamClass); + setBlockDataMode(oldmode); + + fieldsAlreadyRead = true; + } + + + /** + * Registers a <code>ObjectInputValidation</code> to be carried out + * on the object graph currently being deserialized before it is + * returned to the original caller of <code>readObject ()</code>. + * The order of validation for multiple + * <code>ObjectInputValidation</code>s can be controled using + * <code>priority</code>. Validators with higher priorities are + * called first. + * + * @see java.io.ObjectInputValidation + * + * @exception InvalidObjectException <code>validator</code> is + * <code>null</code> + * + * @exception NotActiveException an attempt was made to add a + * validator outside of the <code>readObject</code> method of the + * object currently being deserialized + */ + public void registerValidation(ObjectInputValidation validator, + int priority) + throws InvalidObjectException, NotActiveException + { + if (this.currentObject == null || this.currentObjectStreamClass == null) + throw new NotActiveException("registerValidation called by non-active " + + "class and/or object"); + + if (validator == null) + throw new InvalidObjectException("attempt to add a null " + + "ObjectInputValidation object"); + + this.validators.addElement(new ValidatorAndPriority (validator, + priority)); + } + + + /** + * Called when a class is being deserialized. This is a hook to + * allow subclasses to read in information written by the + * <code>annotateClass (Class)</code> method of an + * <code>ObjectOutputStream</code>. + * + * This implementation looks up the active call stack for a + * <code>ClassLoader</code>; if a <code>ClassLoader</code> is found, + * it is used to load the class associated with <code>osc</code>, + * otherwise, the default system <code>ClassLoader</code> is used. + * + * @exception IOException Exception from underlying + * <code>OutputStream</code>. + * + * @see java.io.ObjectOutputStream#annotateClass (java.lang.Class) + */ + protected Class resolveClass(ObjectStreamClass osc) + throws ClassNotFoundException, IOException + { + if (callersClassLoader == null) + { + callersClassLoader = currentLoader (); + if (Configuration.DEBUG && dump) + { + dumpElementln ("CallersClassLoader = " + callersClassLoader); + } + } + + return Class.forName(osc.getName(), true, callersClassLoader); + } + + /** + * Returns the most recent user defined ClassLoader on the execution stack + * or null if none is found. + */ + // GCJ LOCAL: native method. + private native ClassLoader currentLoader(); + + /** + * Lookup a class stored in the local hashtable. If it is not + * use the global lookup function in ObjectStreamClass to build + * the ObjectStreamClass. This method is requested according to + * the behaviour detected in the JDK by Kaffe's team. + * + * @param clazz Class to lookup in the hash table or for which + * we must build a descriptor. + * @return A valid instance of ObjectStreamClass corresponding + * to the specified class. + */ + private ObjectStreamClass lookupClass(Class clazz) + { + if (clazz == null) + return null; + + ObjectStreamClass oclazz; + oclazz = (ObjectStreamClass)classLookupTable.get(clazz); + if (oclazz == null) + return ObjectStreamClass.lookup(clazz); + else + return oclazz; + } + + /** + * Reconstruct class hierarchy the same way + * {@link java.io.ObjectStreamClass.getObjectStreamClasses(java.lang.Class)} does + * but using lookupClass instead of ObjectStreamClass.lookup. This + * dup is necessary localize the lookup table. Hopefully some future + * rewritings will be able to prevent this. + * + * @param clazz This is the class for which we want the hierarchy. + * + * @return An array of valid {@link java.io.ObjectStreamClass} instances which + * represent the class hierarchy for clazz. + */ + private ObjectStreamClass[] inputGetObjectStreamClasses(Class clazz) + { + ObjectStreamClass osc = lookupClass(clazz); + + if (osc == null) + return new ObjectStreamClass[0]; + else + { + Vector oscs = new Vector(); + + while (osc != null) + { + oscs.addElement(osc); + osc = osc.getSuper(); + } + + int count = oscs.size(); + ObjectStreamClass[] sorted_oscs = new ObjectStreamClass[count]; + + for (int i = count - 1; i >= 0; i--) + sorted_oscs[count - i - 1] = (ObjectStreamClass) oscs.elementAt(i); + + return sorted_oscs; + } + } + + /** + * Allows subclasses to resolve objects that are read from the + * stream with other objects to be returned in their place. This + * method is called the first time each object is encountered. + * + * This method must be enabled before it will be called in the + * serialization process. + * + * @exception IOException Exception from underlying + * <code>OutputStream</code>. + * + * @see #enableResolveObject(boolean) + */ + protected Object resolveObject(Object obj) throws IOException + { + return obj; + } + + + protected Class resolveProxyClass(String[] intfs) + throws IOException, ClassNotFoundException + { + ClassLoader cl = currentLoader(); + + Class[] clss = new Class[intfs.length]; + if(cl == null) + { + for (int i = 0; i < intfs.length; i++) + clss[i] = Class.forName(intfs[i]); + cl = ClassLoader.getSystemClassLoader(); + } + else + for (int i = 0; i < intfs.length; i++) + clss[i] = cl.loadClass(intfs[i]); + try + { + return Proxy.getProxyClass(cl, clss); + } + catch (IllegalArgumentException e) + { + throw new ClassNotFoundException(null, e); + } + } + + /** + * If <code>enable</code> is <code>true</code> and this object is + * trusted, then <code>resolveObject (Object)</code> will be called + * in subsequent calls to <code>readObject (Object)</code>. + * Otherwise, <code>resolveObject (Object)</code> will not be called. + * + * @exception SecurityException This class is not trusted. + */ + protected boolean enableResolveObject (boolean enable) + throws SecurityException + { + if (enable) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new SerializablePermission("enableSubstitution")); + } + + boolean old_val = this.resolveEnabled; + this.resolveEnabled = enable; + return old_val; + } + + /** + * Reads stream magic and stream version information from the + * underlying stream. + * + * @exception IOException Exception from underlying stream. + * + * @exception StreamCorruptedException An invalid stream magic + * number or stream version was read from the stream. + */ + protected void readStreamHeader() + throws IOException, StreamCorruptedException + { + if(dump) dumpElement("STREAM MAGIC "); + if (this.realInputStream.readShort() != STREAM_MAGIC) + throw new StreamCorruptedException("Invalid stream magic number"); + + if(dump) dumpElementln("STREAM VERSION "); + if (this.realInputStream.readShort() != STREAM_VERSION) + throw new StreamCorruptedException("Invalid stream version number"); + } + + public int read() throws IOException + { + if (this.readDataFromBlock) + { + if (this.blockDataPosition >= this.blockDataBytes) + readNextBlock(); + return (this.blockData[this.blockDataPosition++] & 0xff); + } + else + return this.realInputStream.read(); + } + + public int read(byte[] data, int offset, int length) throws IOException + { + if (this.readDataFromBlock) + { + if (this.blockDataPosition + length > this.blockDataBytes) + { + int remain = this.blockDataBytes - this.blockDataPosition; + if (remain != 0) + { + System.arraycopy(this.blockData, this.blockDataPosition, + data, offset, remain); + offset += remain; + length -= remain; + } + readNextBlock (); + } + + System.arraycopy(this.blockData, this.blockDataPosition, + data, offset, length); + this.blockDataPosition += length; + + return length; + } + else + return this.realInputStream.read(data, offset, length); + } + + public int available() throws IOException + { + if (this.readDataFromBlock) + { + if (this.blockDataPosition >= this.blockDataBytes) + readNextBlock (); + + return this.blockDataBytes - this.blockDataPosition; + } + else + return this.realInputStream.available(); + } + + public void close() throws IOException + { + this.realInputStream.close(); + } + + public boolean readBoolean() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode (true); + boolean value = this.dataInputStream.readBoolean (); + if (switchmode) + setBlockDataMode (oldmode); + return value; + } + + public byte readByte() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + byte value = this.dataInputStream.readByte(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public int readUnsignedByte() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 1) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + int value = this.dataInputStream.readUnsignedByte(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public short readShort() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + short value = this.dataInputStream.readShort(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public int readUnsignedShort() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + int value = this.dataInputStream.readUnsignedShort(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public char readChar() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 2) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + char value = this.dataInputStream.readChar(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public int readInt() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + int value = this.dataInputStream.readInt(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public long readLong() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + long value = this.dataInputStream.readLong(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public float readFloat() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 4) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + float value = this.dataInputStream.readFloat(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public double readDouble() throws IOException + { + boolean switchmode = true; + boolean oldmode = this.readDataFromBlock; + if (!oldmode || this.blockDataBytes - this.blockDataPosition >= 8) + switchmode = false; + if (switchmode) + oldmode = setBlockDataMode(true); + double value = this.dataInputStream.readDouble(); + if (switchmode) + setBlockDataMode(oldmode); + return value; + } + + public void readFully(byte data[]) throws IOException + { + this.dataInputStream.readFully(data); + } + + public void readFully(byte data[], int offset, int size) + throws IOException + { + this.dataInputStream.readFully(data, offset, size); + } + + public int skipBytes(int len) throws IOException + { + return this.dataInputStream.skipBytes(len); + } + + /** + * @deprecated + * @see java.io.DataInputStream#readLine () + */ + public String readLine() throws IOException + { + return this.dataInputStream.readLine(); + } + + public String readUTF() throws IOException + { + return this.dataInputStream.readUTF(); + } + + /** + * This class allows a class to specify exactly which fields should + * be read, and what values should be read for these fields. + * + * XXX: finish up comments + */ + public abstract static class GetField + { + public abstract ObjectStreamClass getObjectStreamClass(); + + public abstract boolean defaulted(String name) + throws IOException, IllegalArgumentException; + + public abstract boolean get(String name, boolean defvalue) + throws IOException, IllegalArgumentException; + + public abstract char get(String name, char defvalue) + throws IOException, IllegalArgumentException; + + public abstract byte get(String name, byte defvalue) + throws IOException, IllegalArgumentException; + + public abstract short get(String name, short defvalue) + throws IOException, IllegalArgumentException; + + public abstract int get(String name, int defvalue) + throws IOException, IllegalArgumentException; + + public abstract long get(String name, long defvalue) + throws IOException, IllegalArgumentException; + + public abstract float get(String name, float defvalue) + throws IOException, IllegalArgumentException; + + public abstract double get(String name, double defvalue) + throws IOException, IllegalArgumentException; + + public abstract Object get(String name, Object defvalue) + throws IOException, IllegalArgumentException; + } + + /** + * This method should be called by a method called 'readObject' in the + * deserializing class (if present). It cannot (and should not)be called + * outside of it. Its goal is to read all fields in the real input stream + * and keep them accessible through the {@link #GetField} class. Calling + * this method will not alter the deserializing object. + * + * @return A valid freshly created 'GetField' instance to get access to + * the deserialized stream. + * @throws IOException An input/output exception occured. + * @throws ClassNotFoundException + * @throws NotActiveException + */ + public GetField readFields() + throws IOException, ClassNotFoundException, NotActiveException + { + if (this.currentObject == null || this.currentObjectStreamClass == null) + throw new NotActiveException("readFields called by non-active class and/or object"); + + if (prereadFields != null) + return prereadFields; + + if (fieldsAlreadyRead) + throw new NotActiveException("readFields called but fields already read from" + + " stream (by defaultReadObject or readFields)"); + + final ObjectStreamClass clazz = this.currentObjectStreamClass; + final byte[] prim_field_data = new byte[clazz.primFieldSize]; + final Object[] objs = new Object[clazz.objectFieldCount]; + + // Apparently Block data is not used with GetField as per + // empirical evidence against JDK 1.2. Also see Mauve test + // java.io.ObjectInputOutput.Test.GetPutField. + boolean oldmode = setBlockDataMode(false); + readFully(prim_field_data); + for (int i = 0; i < objs.length; ++ i) + objs[i] = readObject(); + setBlockDataMode(oldmode); + + prereadFields = new GetField() + { + public ObjectStreamClass getObjectStreamClass() + { + return clazz; + } + + public boolean defaulted(String name) + throws IOException, IllegalArgumentException + { + ObjectStreamField f = clazz.getField(name); + + /* First if we have a serialized field use the descriptor */ + if (f != null) + { + /* It is in serialPersistentFields but setClass tells us + * it should not be set. This value is defaulted. + */ + if (f.isPersistent() && !f.isToSet()) + return true; + + return false; + } + + /* This is not a serialized field. There should be + * a default value only if the field really exists. + */ + try + { + return (clazz.forClass().getDeclaredField (name) != null); + } + catch (NoSuchFieldException e) + { + throw new IllegalArgumentException(e.getMessage()); + } + } + + public boolean get(String name, boolean defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Boolean.TYPE); + + if (field == null) + return defvalue; + + return prim_field_data[field.getOffset()] == 0 ? false : true; + } + + public char get(String name, char defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Character.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return (char)(((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public byte get(String name, byte defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Byte.TYPE); + + if (field == null) + return defvalue; + + return prim_field_data[field.getOffset()]; + } + + public short get(String name, short defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Short.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return (short)(((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public int get(String name, int defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Integer.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return ((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF); + } + + public long get(String name, long defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Long.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return (long)(((prim_field_data[off++] & 0xFFL) << 56) + | ((prim_field_data[off++] & 0xFFL) << 48) + | ((prim_field_data[off++] & 0xFFL) << 40) + | ((prim_field_data[off++] & 0xFFL) << 32) + | ((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public float get(String name, float defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Float.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return Float.intBitsToFloat(((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF)); + } + + public double get(String name, double defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = getField(name, Double.TYPE); + + if (field == null) + return defvalue; + + int off = field.getOffset(); + + return Double.longBitsToDouble + ( (long) (((prim_field_data[off++] & 0xFFL) << 56) + | ((prim_field_data[off++] & 0xFFL) << 48) + | ((prim_field_data[off++] & 0xFFL) << 40) + | ((prim_field_data[off++] & 0xFFL) << 32) + | ((prim_field_data[off++] & 0xFF) << 24) + | ((prim_field_data[off++] & 0xFF) << 16) + | ((prim_field_data[off++] & 0xFF) << 8) + | (prim_field_data[off] & 0xFF))); + } + + public Object get(String name, Object defvalue) + throws IOException, IllegalArgumentException + { + ObjectStreamField field = + getField(name, defvalue == null ? null : defvalue.getClass ()); + + if (field == null) + return defvalue; + + return objs[field.getOffset()]; + } + + private ObjectStreamField getField(String name, Class type) + throws IllegalArgumentException + { + ObjectStreamField field = clazz.getField(name); + boolean illegal = false; + + try + { + try + { + Class field_type = field.getType(); + + if (type == field_type || + (type == null && !field_type.isPrimitive())) + { + /* See defaulted */ + return field; + } + + illegal = true; + throw new IllegalArgumentException + ("Field requested is of type " + + field_type.getName() + + ", but requested type was " + + (type == null ? "Object" : type.getName())); + } + catch (NullPointerException _) + { + /* Here we catch NullPointerException, because it may + only come from the call 'field.getType()'. If field + is null, we have to return null and classpath ethic + say we must try to avoid 'if (xxx == null)'. + */ + } + catch (IllegalArgumentException e) + { + throw e; + } + + return null; + } + finally + { + /* If this is an unassigned field we should return + * the default value. + */ + if (!illegal && field != null && !field.isToSet() && field.isPersistent()) + return null; + + /* We do not want to modify transient fields. They should + * be left to 0. + */ + try + { + Field f = clazz.forClass().getDeclaredField(name); + if (Modifier.isTransient(f.getModifiers())) + throw new IllegalArgumentException + ("no such field (non transient) " + name); + if (field == null && f.getType() != type) + throw new IllegalArgumentException + ("Invalid requested type for field " + name); + } + catch (NoSuchFieldException e) + { + if (field == null) + throw new IllegalArgumentException(e.getMessage()); + } + + } + } + }; + + fieldsAlreadyRead = true; + return prereadFields; + } + + /** + * Protected constructor that allows subclasses to override + * deserialization. This constructor should be called by subclasses + * that wish to override <code>readObject (Object)</code>. This + * method does a security check <i>NOTE: currently not + * implemented</i>, then sets a flag that informs + * <code>readObject (Object)</code> to call the subclasses + * <code>readObjectOverride (Object)</code> method. + * + * @see #readObjectOverride() + */ + protected ObjectInputStream() + throws IOException, SecurityException + { + SecurityManager sec_man = System.getSecurityManager(); + if (sec_man != null) + sec_man.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); + this.useSubclassMethod = true; + } + + /** + * This method allows subclasses to override the default + * de serialization mechanism provided by + * <code>ObjectInputStream</code>. To make this method be used for + * writing objects, subclasses must invoke the 0-argument + * constructor on this class from their constructor. + * + * @see #ObjectInputStream() + */ + protected Object readObjectOverride() + throws ClassNotFoundException, IOException, OptionalDataException + { + throw new IOException("Subclass of ObjectInputStream must implement readObjectOverride"); + } + + /** + * Assigns the next available handle to <code>obj</code>. + * + * @param obj The object for which we want a new handle. + * @return A valid handle for the specified object. + */ + private int assignNewHandle(Object obj) + { + this.objectLookupTable.put(new Integer(this.nextOID), + new ObjectIdentityWrapper(obj)); + return this.nextOID++; + } + + private Object processResolution(ObjectStreamClass osc, Object obj, int handle) + throws IOException + { + if (osc != null && obj instanceof Serializable) + { + try + { + Method m = osc.readResolveMethod; + if(m != null) + { + obj = m.invoke(obj, new Object[] {}); + } + } + catch (IllegalAccessException ignore) + { + } + catch (InvocationTargetException exception) + { + Throwable cause = exception.getCause(); + if (cause instanceof ObjectStreamException) + throw (ObjectStreamException) cause; + else if (cause instanceof RuntimeException) + throw (RuntimeException) cause; + else if (cause instanceof Error) + throw (Error) cause; + } + } + + if (this.resolveEnabled) + obj = resolveObject(obj); + + this.objectLookupTable.put(new Integer(handle), + new ObjectIdentityWrapper(obj)); + + return obj; + } + + private void clearHandles() + { + this.objectLookupTable.clear(); + this.nextOID = baseWireHandle; + } + + private void readNextBlock() throws IOException + { + readNextBlock(this.realInputStream.readByte()); + } + + private void readNextBlock(byte marker) throws IOException + { + if (marker == TC_BLOCKDATA) + { + if(dump) dumpElement("BLOCK DATA SIZE="); + this.blockDataBytes = this.realInputStream.readUnsignedByte(); + if(dump) dumpElementln (Integer.toString(this.blockDataBytes)); + } + else if (marker == TC_BLOCKDATALONG) + { + if(dump) dumpElement("BLOCK DATA LONG SIZE="); + this.blockDataBytes = this.realInputStream.readInt(); + if(dump) dumpElementln (Integer.toString(this.blockDataBytes)); + } + else + { + throw new EOFException("Attempt to read primitive data, but no data block is active."); + } + + if (this.blockData.length < this.blockDataBytes) + this.blockData = new byte[this.blockDataBytes]; + + this.realInputStream.readFully (this.blockData, 0, this.blockDataBytes); + this.blockDataPosition = 0; + } + + private void readArrayElements (Object array, Class clazz) + throws ClassNotFoundException, IOException + { + if (clazz.isPrimitive()) + { + if (clazz == Boolean.TYPE) + { + boolean[] cast_array = (boolean[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readBoolean(); + return; + } + if (clazz == Byte.TYPE) + { + byte[] cast_array = (byte[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readByte(); + return; + } + if (clazz == Character.TYPE) + { + char[] cast_array = (char[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readChar(); + return; + } + if (clazz == Double.TYPE) + { + double[] cast_array = (double[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readDouble(); + return; + } + if (clazz == Float.TYPE) + { + float[] cast_array = (float[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readFloat(); + return; + } + if (clazz == Integer.TYPE) + { + int[] cast_array = (int[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readInt(); + return; + } + if (clazz == Long.TYPE) + { + long[] cast_array = (long[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readLong(); + return; + } + if (clazz == Short.TYPE) + { + short[] cast_array = (short[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = this.realInputStream.readShort(); + return; + } + } + else + { + Object[] cast_array = (Object[])array; + for (int i=0; i < cast_array.length; i++) + cast_array[i] = readObject(); + } + } + + private void readFields (Object obj, ObjectStreamClass stream_osc) + throws ClassNotFoundException, IOException + { + ObjectStreamField[] fields = stream_osc.fieldMapping; + + for (int i = 0; i < fields.length; i += 2) + { + ObjectStreamField stream_field = fields[i]; + ObjectStreamField real_field = fields[i + 1]; + boolean read_value = (stream_field != null && stream_field.getOffset() >= 0 && stream_field.isToSet()); + boolean set_value = (real_field != null && real_field.isToSet()); + String field_name; + char type; + + if (stream_field != null) + { + field_name = stream_field.getName(); + type = stream_field.getTypeCode(); + } + else + { + field_name = real_field.getName(); + type = real_field.getTypeCode(); + } + + switch(type) + { + case 'Z': + { + boolean value = + read_value ? this.realInputStream.readBoolean() : false; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setBooleanField(obj, value); + break; + } + case 'B': + { + byte value = + read_value ? this.realInputStream.readByte() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setByteField(obj, value); + break; + } + case 'C': + { + char value = + read_value ? this.realInputStream.readChar(): 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setCharField(obj, value); + break; + } + case 'D': + { + double value = + read_value ? this.realInputStream.readDouble() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setDoubleField(obj, value); + break; + } + case 'F': + { + float value = + read_value ? this.realInputStream.readFloat() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setFloatField(obj, value); + break; + } + case 'I': + { + int value = + read_value ? this.realInputStream.readInt() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setIntField(obj, value); + break; + } + case 'J': + { + long value = + read_value ? this.realInputStream.readLong() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setLongField(obj, value); + break; + } + case 'S': + { + short value = + read_value ? this.realInputStream.readShort() : 0; + if (dump && read_value && set_value) + dumpElementln(" " + field_name + ": " + value); + if (set_value) + real_field.setShortField(obj, value); + break; + } + case 'L': + case '[': + { + Object value = + read_value ? readObject() : null; + if (set_value) + real_field.setObjectField(obj, value); + break; + } + default: + throw new InternalError("Invalid type code: " + type); + } + } + } + + // Toggles writing primitive data to block-data buffer. + private boolean setBlockDataMode (boolean on) + { + boolean oldmode = this.readDataFromBlock; + this.readDataFromBlock = on; + + if (on) + this.dataInputStream = this.blockDataInput; + else + this.dataInputStream = this.realInputStream; + return oldmode; + } + + // returns a new instance of REAL_CLASS that has been constructed + // only to the level of CONSTRUCTOR_CLASS (a super class of REAL_CLASS) + private Object newObject (Class real_class, Constructor constructor) + throws ClassNotFoundException, IOException + { + if (constructor == null) + throw new InvalidClassException("Missing accessible no-arg base class constructor for " + real_class.getName()); + try + { + return allocateObject(real_class, constructor.getDeclaringClass(), constructor); + } + catch (InstantiationException e) + { + throw new ClassNotFoundException + ("Instance of " + real_class + " could not be created"); + } + } + + // runs all registered ObjectInputValidations in prioritized order + // on OBJ + private void invokeValidators() throws InvalidObjectException + { + Object[] validators = new Object[this.validators.size()]; + this.validators.copyInto (validators); + Arrays.sort (validators); + + try + { + for (int i=0; i < validators.length; i++) + ((ObjectInputValidation)validators[i]).validateObject(); + } + finally + { + this.validators.removeAllElements(); + } + } + + private void callReadMethod (Method readObject, Class klass, Object obj) + throws ClassNotFoundException, IOException + { + try + { + readObject.invoke(obj, new Object[] { this }); + } + catch (InvocationTargetException x) + { + /* Rethrow if possible. */ + Throwable exception = x.getTargetException(); + if (exception instanceof RuntimeException) + throw (RuntimeException) exception; + if (exception instanceof IOException) + throw (IOException) exception; + if (exception instanceof ClassNotFoundException) + throw (ClassNotFoundException) exception; + + throw new IOException("Exception thrown from readObject() on " + + klass + ": " + exception.getClass().getName()); + } + catch (Exception x) + { + throw new IOException("Failure invoking readObject() on " + + klass + ": " + x.getClass().getName()); + } + + // Invalidate fields which has been read through readFields. + prereadFields = null; + } + + private native Object allocateObject(Class clazz, Class constr_clazz, Constructor constructor) + throws InstantiationException; + + private static final int BUFFER_SIZE = 1024; + + private DataInputStream realInputStream; + private DataInputStream dataInputStream; + private DataInputStream blockDataInput; + private int blockDataPosition; + private int blockDataBytes; + private byte[] blockData; + private boolean useSubclassMethod; + private int nextOID; + private boolean resolveEnabled; + private Hashtable objectLookupTable; + private Object currentObject; + private ObjectStreamClass currentObjectStreamClass; + private boolean readDataFromBlock; + private boolean isDeserializing; + private boolean fieldsAlreadyRead; + private Vector validators; + private Hashtable classLookupTable; + private GetField prereadFields; + + private ClassLoader callersClassLoader; + private static boolean dump; + + // The nesting depth for debugging output + private int depth = 0; + + private void dumpElement (String msg) + { + System.out.print(msg); + } + + private void dumpElementln (String msg) + { + System.out.println(msg); + for (int i = 0; i < depth; i++) + System.out.print (" "); + System.out.print (Thread.currentThread() + ": "); + } + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary ("javaio"); + } + } + + // used to keep a prioritized list of object validators + private static final class ValidatorAndPriority implements Comparable + { + int priority; + ObjectInputValidation validator; + + ValidatorAndPriority (ObjectInputValidation validator, int priority) + { + this.priority = priority; + this.validator = validator; + } + + public int compareTo (Object o) + { + ValidatorAndPriority vap = (ValidatorAndPriority)o; + return this.priority - vap.priority; + } + } +} + diff --git a/gcc-4.2.1/libjava/java/io/OutputStreamWriter.java b/gcc-4.2.1/libjava/java/io/OutputStreamWriter.java new file mode 100644 index 000000000..aac1684c6 --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/OutputStreamWriter.java @@ -0,0 +1,347 @@ +/* OutputStreamWriter.java -- Writer that converts chars to bytes + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import gnu.gcj.convert.UnicodeToBytes; +import gnu.gcj.convert.CharsetToBytesAdaptor; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; + +/** + * This class writes characters to an output stream that is byte oriented + * It converts the chars that are written to bytes using an encoding layer, + * which is specific to a particular encoding standard. The desired + * encoding can either be specified by name, or if no encoding is specified, + * the system default encoding will be used. The system default encoding + * name is determined from the system property <code>file.encoding</code>. + * The only encodings that are guaranteed to be available are "8859_1" + * (the Latin-1 character set) and "UTF8". Unfortunately, Java does not + * provide a mechanism for listing the encodings that are supported in + * a given implementation. + * <p> + * Here is a list of standard encoding names that may be available: + * <p> + * <ul> + * <li>8859_1 (ISO-8859-1/Latin-1) + * <li>8859_2 (ISO-8859-2/Latin-2) + * <li>8859_3 (ISO-8859-3/Latin-3) + * <li>8859_4 (ISO-8859-4/Latin-4) + * <li>8859_5 (ISO-8859-5/Latin-5) + * <li>8859_6 (ISO-8859-6/Latin-6) + * <li>8859_7 (ISO-8859-7/Latin-7) + * <li>8859_8 (ISO-8859-8/Latin-8) + * <li>8859_9 (ISO-8859-9/Latin-9) + * <li>ASCII (7-bit ASCII) + * <li>UTF8 (UCS Transformation Format-8) + * <li>More Later + * </ul> + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner (bothner@cygnus.com) + * @date April 17, 1998. + */ +public class OutputStreamWriter extends Writer +{ + BufferedOutputStream out; + + /** + * This is the byte-character encoder class that does the writing and + * translation of characters to bytes before writing to the underlying + * class. + */ + UnicodeToBytes converter; + + /* Temporary buffer. */ + private char[] work; + private int wcount; + + private OutputStreamWriter(OutputStream out, UnicodeToBytes encoder) + { + this.out = out instanceof BufferedOutputStream + ? (BufferedOutputStream) out + : new BufferedOutputStream(out, 250); + /* Don't need to call super(out) here as long as the lock gets set. */ + this.lock = out; + this.converter = encoder; + } + + /** + * This method initializes a new instance of <code>OutputStreamWriter</code> + * to write to the specified stream using a caller supplied character + * encoding scheme. Note that due to a deficiency in the Java language + * design, there is no way to determine which encodings are supported. + * + * @param out The <code>OutputStream</code> to write to + * @param encoding_scheme The name of the encoding scheme to use for + * character to byte translation + * + * @exception UnsupportedEncodingException If the named encoding is + * not available. + */ + public OutputStreamWriter (OutputStream out, String encoding_scheme) + throws UnsupportedEncodingException + { + this(out, UnicodeToBytes.getEncoder(encoding_scheme)); + } + + /** + * This method initializes a new instance of <code>OutputStreamWriter</code> + * to write to the specified stream using the default encoding. + * + * @param out The <code>OutputStream</code> to write to + */ + public OutputStreamWriter (OutputStream out) + { + this(out, UnicodeToBytes.getDefaultEncoder()); + } + + /** + * This method initializes a new instance of <code>OutputStreamWriter</code> + * to write to the specified stream using a given <code>Charset</code>. + * + * @param out The <code>OutputStream</code> to write to + * @param cs The <code>Charset</code> of the encoding to use + */ + public OutputStreamWriter(OutputStream out, Charset cs) + { + this(out, new CharsetToBytesAdaptor(cs)); + } + + /** + * This method initializes a new instance of <code>OutputStreamWriter</code> + * to write to the specified stream using a given + * <code>CharsetEncoder</code>. + * + * @param out The <code>OutputStream</code> to write to + * @param enc The <code>CharsetEncoder</code> to encode the output with + */ + public OutputStreamWriter(OutputStream out, CharsetEncoder enc) + { + this(out, new CharsetToBytesAdaptor(enc)); + } + + /** + * This method closes this stream, and the underlying + * <code>OutputStream</code> + * + * @exception IOException If an error occurs + */ + public void close () throws IOException + { + synchronized (lock) + { + if (out != null) + { + converter.setFinished(); + flush(); + out.close(); + out = null; + } + work = null; + } + } + + /** + * This method returns the name of the character encoding scheme currently + * in use by this stream. If the stream has been closed, then this method + * may return <code>null</code>. + * + * @return The encoding scheme name + */ + public String getEncoding () + { + return out != null ? converter.getName() : null; + } + + /** + * This method flushes any buffered bytes to the underlying output sink. + * + * @exception IOException If an error occurs + */ + public void flush () throws IOException + { + synchronized (lock) + { + if (out == null) + throw new IOException("Stream closed"); + + // Always write -- if we are close()ing then we want to make + // sure the converter is flushed. + if (work == null) + work = new char[100]; + writeChars(work, 0, wcount); + wcount = 0; + + out.flush(); + } + } + + /** + * This method writes <code>count</code> characters from the specified + * array to the output stream starting at position <code>offset</code> + * into the array. + * + * @param buf The array of character to write from + * @param offset The offset into the array to start writing chars from + * @param count The number of chars to write. + * + * @exception IOException If an error occurs + */ + public void write (char[] buf, int offset, int count) throws IOException + { + synchronized (lock) + { + if (out == null) + throw new IOException("Stream closed"); + + if (wcount > 0) + { + writeChars(work, 0, wcount); + wcount = 0; + } + writeChars(buf, offset, count); + } + } + + /* + * Writes characters through to the inferior BufferedOutputStream. + * Ignores wcount and the work buffer. + */ + private void writeChars(char[] buf, int offset, int count) + throws IOException + { + do + { + // We must flush if out.count == out.buf.length. + // It is probably a good idea to flush if out.buf is almost full. + // This test is an approximation for "almost full". + if (out.count + count >= out.buf.length) + { + out.flush(); + if (out.count != 0) + throw new IOException("unable to flush output byte buffer"); + } + converter.setOutput(out.buf, out.count); + int converted = converter.write(buf, offset, count); + // Must set this before we flush the output stream, because + // flushing will reset 'out.count'. + out.count = converter.count; + // Flush if we cannot make progress. + if (converted == 0 && out.count == converter.count) + { + out.flush(); + if (out.count != 0) + throw new IOException("unable to flush output byte buffer"); + } + offset += converted; + count -= converted; + } + while (count > 0 || converter.havePendingBytes()); + } + + /** + * This method writes <code>count</code> bytes from the specified + * <code>String</code> starting at position <code>offset</code> into the + * <code>String</code>. + * + * @param str The <code>String</code> to write chars from + * @param offset The position in the <code>String</code> to start + * writing chars from + * @param count The number of chars to write + * + * @exception IOException If an error occurs + */ + public void write (String str, int offset, int count) throws IOException + { + synchronized (lock) + { + if (out == null) + throw new IOException("Stream closed"); + + if (work == null) + work = new char[100]; + int wlength = work.length; + while (count > 0) + { + int size = count; + if (wcount + size > wlength) + { + if (2*wcount > wlength) + { + writeChars(work, 0, wcount); + wcount = 0; + } + if (wcount + size > wlength) + size = wlength - wcount; + } + str.getChars(offset, offset+size, work, wcount); + offset += size; + count -= size; + wcount += size; + } + } + } + + /** + * This method writes a single character to the output stream. + * + * @param ch The char to write, passed as an int. + * + * @exception IOException If an error occurs + */ + public void write (int ch) throws IOException + { + synchronized (lock) + { + if (out == null) + throw new IOException("Stream closed"); + + if (work == null) + work = new char[100]; + if (wcount >= work.length) + { + writeChars(work, 0, wcount); + wcount = 0; + } + work[wcount++] = (char) ch; + } + } + +} // class OutputStreamWriter + diff --git a/gcc-4.2.1/libjava/java/io/PrintStream.java b/gcc-4.2.1/libjava/java/io/PrintStream.java new file mode 100644 index 000000000..dc26edafd --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/PrintStream.java @@ -0,0 +1,566 @@ +/* PrintStream.java -- OutputStream for printing output + Copyright (C) 1998, 1999, 2001, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import gnu.gcj.convert.UnicodeToBytes; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * Status: Believed complete and correct to 1.3 + */ + +/** + * This class prints Java primitive values and object to a stream as + * text. None of the methods in this class throw an exception. However, + * errors can be detected by calling the <code>checkError()</code> method. + * Additionally, this stream can be designated as "autoflush" when + * created so that any writes are automatically flushed to the underlying + * output sink when the current line is terminated. + * <p> + * This class converts char's into byte's using the system default encoding. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class PrintStream extends FilterOutputStream +{ + /* Notice the implementation is quite similar to OutputStreamWriter. + * This leads to some minor duplication, because neither inherits + * from the other, and we want to maximize performance. */ + + // Line separator string. + private static final char[] line_separator + = System.getProperty("line.separator").toCharArray(); + + UnicodeToBytes converter; + + // Work buffer of characters for converter. + char[] work = new char[100]; + // Work buffer of bytes where we temporarily keep converter output. + byte[] work_bytes = new byte[100]; + + /** + * This boolean indicates whether or not an error has ever occurred + * on this stream. + */ + private boolean error_occurred = false; + + /** + * This is <code>true</code> if auto-flush is enabled, + * <code>false</code> otherwise + */ + private boolean auto_flush; + + /** + * This method intializes a new <code>PrintStream</code> object to write + * to the specified output sink. + * + * @param out The <code>OutputStream</code> to write to. + */ + public PrintStream (OutputStream out) + { + this (out, false); + } + + /** + * This method intializes a new <code>PrintStream</code> object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every <code>print</code> or <code>println</code> call, when the + * <code>write</code> methods with array arguments are called, or when a + * single new-line character is written. + * <p> + * + * @param out The <code>OutputStream</code> to write to. + * @param auto_flush <code>true</code> to flush the stream after every + * line, <code>false</code> otherwise + */ + public PrintStream (OutputStream out, boolean auto_flush) + { + super (out); + + converter = UnicodeToBytes.getDefaultEncoder(); + this.auto_flush = auto_flush; + } + + /** + * This method intializes a new <code>PrintStream</code> object to write + * to the specified output sink. This constructor also allows "auto-flush" + * functionality to be specified where the stream will be flushed after + * every <code>print</code> or <code>println</code> call, when the + * <code>write</code> methods with array arguments are called, or when a + * single new-line character is written. + * <p> + * + * @param out The <code>OutputStream</code> to write to. + * @param auto_flush <code>true</code> to flush the stream after every + * line, <code>false</code> otherwise + * @param encoding The name of the character encoding to use for this + * object. + */ + public PrintStream (OutputStream out, boolean auto_flush, String encoding) + throws UnsupportedEncodingException + { + super (out); + + converter = UnicodeToBytes.getEncoder (encoding); + this.auto_flush = auto_flush; + } + + /** + * This method checks to see if an error has occurred on this stream. Note + * that once an error has occurred, this method will continue to report + * <code>true</code> forever for this stream. Before checking for an + * error condition, this method flushes the stream. + * + * @return <code>true</code> if an error has occurred, + * <code>false</code> otherwise + */ + public boolean checkError () + { + flush (); + return error_occurred; + } + + /** + * This method can be called by subclasses to indicate that an error + * has occurred and should be reported by <code>checkError</code>. + */ + protected void setError () + { + error_occurred = true; + } + + /** + * This method closes this stream and all underlying streams. + */ + public void close () + { + try + { + converter.setFinished(); + writeChars(new char[0], 0, 0); + flush(); + out.close(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + /** + * This method flushes any buffered bytes to the underlying stream and + * then flushes that stream as well. + */ + public void flush () + { + try + { + out.flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + private synchronized void print (String str, boolean println) + { + try + { + writeChars(str, 0, str.length()); + if (println) + writeChars(line_separator, 0, line_separator.length); + if (auto_flush) + flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + private synchronized void print (char[] chars, int pos, int len, + boolean println) + { + try + { + writeChars(chars, pos, len); + if (println) + writeChars(line_separator, 0, line_separator.length); + if (auto_flush) + flush(); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread().interrupt(); + } + catch (IOException e) + { + setError (); + } + } + + private void writeChars(char[] buf, int offset, int count) + throws IOException + { + do + { + converter.setOutput(work_bytes, 0); + int converted = converter.write(buf, offset, count); + offset += converted; + count -= converted; + out.write(work_bytes, 0, converter.count); + } + while (count > 0 || converter.havePendingBytes()); + } + + private void writeChars(String str, int offset, int count) + throws IOException + { + do + { + converter.setOutput(work_bytes, 0); + int converted = converter.write(str, offset, count, work); + offset += converted; + count -= converted; + out.write(work_bytes, 0, converter.count); + } + while (count > 0 || converter.havePendingBytes()); + } + + /** + * This methods prints a boolean value to the stream. <code>true</code> + * values are printed as "true" and <code>false</code> values are printed + * as "false". + * + * @param bool The <code>boolean</code> value to print + */ + public void print (boolean bool) + { + print(String.valueOf(bool), false); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * + * @param inum The <code>int</code> value to be printed + */ + public void print (int inum) + { + print(String.valueOf(inum), false); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * + * @param lnum The <code>long</code> value to be printed + */ + public void print (long lnum) + { + print(String.valueOf(lnum), false); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * + * @param fnum The <code>float</code> value to be printed + */ + public void print (float fnum) + { + print(String.valueOf(fnum), false); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * + * @param dnum The <code>double</code> value to be printed + */ + public void print (double dnum) + { + print(String.valueOf(dnum), false); + } + + /** + * This method prints an <code>Object</code> to the stream. The actual + * value printed is determined by calling the <code>String.valueOf()</code> + * method. + * + * @param obj The <code>Object</code> to print. + */ + public void print (Object obj) + { + print(obj == null ? "null" : obj.toString(), false); + } + + /** + * This method prints a <code>String</code> to the stream. The actual + * value printed depends on the system default encoding. + * + * @param str The <code>String</code> to print. + */ + public void print (String str) + { + print(str == null ? "null" : str, false); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + * + * @param ch The <code>char</code> value to be printed + */ + public synchronized void print (char ch) + { + work[0] = ch; + print(work, 0, 1, false); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + * + * @param charArray The array of characters to print. + */ + public void print (char[] charArray) + { + print(charArray, 0, charArray.length, false); + } + + /** + * This method prints a line separator sequence to the stream. The value + * printed is determined by the system property <xmp>line.separator</xmp> + * and is not necessarily the Unix '\n' newline character. + */ + public void println () + { + print(line_separator, 0, line_separator.length, false); + } + + /** + * This methods prints a boolean value to the stream. <code>true</code> + * values are printed as "true" and <code>false</code> values are printed + * as "false". + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param bool The <code>boolean</code> value to print + */ + public void println (boolean bool) + { + print(String.valueOf(bool), true); + } + + /** + * This method prints an integer to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param inum The <code>int</code> value to be printed + */ + public void println (int inum) + { + print(String.valueOf(inum), true); + } + + /** + * This method prints a long to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param lnum The <code>long</code> value to be printed + */ + public void println (long lnum) + { + print(String.valueOf(lnum), true); + } + + /** + * This method prints a float to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param fnum The <code>float</code> value to be printed + */ + public void println (float fnum) + { + print(String.valueOf(fnum), true); + } + + /** + * This method prints a double to the stream. The value printed is + * determined using the <code>String.valueOf()</code> method. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param dnum The <code>double</code> value to be printed + */ + public void println (double dnum) + { + print(String.valueOf(dnum), true); + } + + /** + * This method prints an <code>Object</code> to the stream. The actual + * value printed is determined by calling the <code>String.valueOf()</code> + * method. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param obj The <code>Object</code> to print. + */ + public void println (Object obj) + { + print(obj == null ? "null" : obj.toString(), true); + } + + /** + * This method prints a <code>String</code> to the stream. The actual + * value printed depends on the system default encoding. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param str The <code>String</code> to print. + */ + public void println (String str) + { + print (str == null ? "null" : str, true); + } + + /** + * This method prints a char to the stream. The actual value printed is + * determined by the character encoding in use. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param ch The <code>char</code> value to be printed + */ + public synchronized void println (char ch) + { + work[0] = ch; + print(work, 0, 1, true); + } + + /** + * This method prints an array of characters to the stream. The actual + * value printed depends on the system default encoding. + * <p> + * This method prints a line termination sequence after printing the value. + * + * @param charArray The array of characters to print. + */ + public void println (char[] charArray) + { + print(charArray, 0, charArray.length, true); + } + + /** + * This method writes a byte of data to the stream. If auto-flush is + * enabled, printing a newline character will cause the stream to be + * flushed after the character is written. + * + * @param oneByte The byte to be written + */ + public void write (int oneByte) + { + try + { + out.write (oneByte & 0xff); + + if (auto_flush && (oneByte == '\n')) + flush (); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread ().interrupt (); + } + catch (IOException e) + { + setError (); + } + } + + /** + * This method writes <code>len</code> bytes from the specified array + * starting at index <code>offset</code> into the array. + * + * @param buffer The array of bytes to write + * @param offset The index into the array to start writing from + * @param len The number of bytes to write + */ + public void write (byte[] buffer, int offset, int len) + { + try + { + out.write (buffer, offset, len); + + if (auto_flush) + flush (); + } + catch (InterruptedIOException iioe) + { + Thread.currentThread ().interrupt (); + } + catch (IOException e) + { + setError (); + } + } +} // class PrintStream + diff --git a/gcc-4.2.1/libjava/java/io/VMObjectStreamClass.java b/gcc-4.2.1/libjava/java/io/VMObjectStreamClass.java new file mode 100644 index 000000000..3900855ab --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/VMObjectStreamClass.java @@ -0,0 +1,140 @@ +/* VMObjectStreamClass.java -- VM helper functions for ObjectStreamClass + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.io; + +import java.lang.reflect.Field; + +final class VMObjectStreamClass +{ + /** + * Returns true if CLAZZ has a static class initializer + * (a.k.a. <clinit>). + */ + static native boolean hasClassInitializer (Class clazz); + + /** + * Sets the value of the specified "double" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setDoubleNative(Field field, Object obj, double val); + + /** + * Sets the value of the specified "float" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setFloatNative(Field field, Object obj, float val); + + /** + * Sets the value of the specified "long" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setLongNative(Field field, Object obj, long val); + + /** + * Sets the value of the specified "int" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setIntNative(Field field, Object obj, int val); + + /** + * Sets the value of the specified "short" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setShortNative(Field field, Object obj, short val); + + /** + * Sets the value of the specified "char" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setCharNative(Field field, Object obj, char val); + + /** + * Sets the value of the specified "byte" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setByteNative(Field field, Object obj, byte val); + + /** + * Sets the value of the specified "boolean" field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setBooleanNative(Field field, Object obj, boolean val); + + /** + * Sets the value of the specified object field, allowing final values + * to be assigned. + * + * @param field Field to set the value. + * @param obj Instance which will have its field set. + * @param val Value to put in the field. + */ + static native void setObjectNative(Field field, Object obj, Object val); +} diff --git a/gcc-4.2.1/libjava/java/io/natFilePosix.cc b/gcc-4.2.1/libjava/java/io/natFilePosix.cc new file mode 100644 index 000000000..c9bf858f1 --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/natFilePosix.cc @@ -0,0 +1,458 @@ +// natFile.cc - Native part of File class for POSIX. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006 + Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdio.h> +#include <errno.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <fcntl.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#ifdef HAVE_DIRENT_H +#include <dirent.h> +#endif +#include <string.h> +#include <utime.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/io/File.h> +#include <java/io/IOException.h> +#include <java/util/ArrayList.h> +#include <java/lang/String.h> +#include <java/io/FilenameFilter.h> +#include <java/io/FileFilter.h> +#include <java/lang/System.h> + +jboolean +java::io::File::_access (jint query) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + JvAssert (query == READ || query == WRITE || query == EXISTS); +#ifdef HAVE_ACCESS + int mode; + if (query == READ) + mode = R_OK; + else if (query == WRITE) + mode = W_OK; + else + mode = F_OK; + return ::access (buf, mode) == 0; +#else + return false; +#endif +} + +jboolean +java::io::File::_stat (jint query) +{ + if (query == ISHIDDEN) + return getName()->charAt(0) == '.'; + +#ifdef HAVE_STAT + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + + struct stat sb; + if (::stat (buf, &sb)) + return false; + + JvAssert (query == DIRECTORY || query == ISFILE); + jboolean r = S_ISDIR (sb.st_mode); + return query == DIRECTORY ? r : ! r; +#else + return false; +#endif +} + +jlong +java::io::File::attr (jint query) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + +#ifdef HAVE_STAT + struct stat sb; + // FIXME: not sure about return value here. + if (::stat (buf, &sb)) + return 0; + + JvAssert (query == MODIFIED || query == LENGTH); + return query == MODIFIED ? (jlong)sb.st_mtime * 1000 : sb.st_size; +#else + // There's no good choice here. + return 23; +#endif +} + +// These two methods are used to maintain dynamically allocated +// buffers for getCanonicalPath without the overhead of calling +// realloc every time a buffer is modified. Buffers are sized +// at the smallest multiple of CHUNKSIZ that is greater than or +// equal to the desired length. The default CHUNKSIZ is 256, +// longer than most paths, so in most cases a getCanonicalPath +// will require only one malloc per buffer. + +#define CHUNKLOG 8 +#define CHUNKSIZ (1 << CHUNKLOG) + +static int +nextChunkSize (int size) +{ + return ((size >> CHUNKLOG) + ((size & (CHUNKSIZ - 1)) ? 1 : 0)) << CHUNKLOG; +} + +static char * +maybeGrowBuf (char *buf, int *size, int required) +{ + if (required > *size) + { + *size = nextChunkSize (required); + buf = (char *) _Jv_Realloc (buf, *size); + } + return buf; +} + +// Return a canonical representation of the pathname of this file. On +// the GNU system this involves the removal of redundant separators, +// references to "." and "..", and symbolic links. +// +// The conversion proceeds on a component-by-component basis: symbolic +// links and references to ".." are resolved as and when they occur. +// This means that if "/foo/bar" is a symbolic link to "/baz" then the +// canonical form of "/foo/bar/.." is "/" and not "/foo". +// +// In order to mimic the behaviour of proprietary JVMs, non-existant +// path components are allowed (a departure from the normal GNU system +// convention). This means that if "/foo/bar" is a symbolic link to +// "/baz", the canonical form of "/non-existant-directory/../foo/bar" +// is "/baz". + +jstring +java::io::File::getCanonicalPath (void) +{ + jstring path = getAbsolutePath (); + + int len = JvGetStringUTFLength (path); + int srcl = nextChunkSize (len + 1); + char *src = (char *) _Jv_Malloc (srcl); + JvGetStringUTFRegion (path, 0, path->length(), src); + src[len] = '\0'; + int srci = 1; + + int dstl = nextChunkSize (2); + char *dst = (char *) _Jv_Malloc (dstl); + dst[0] = '/'; + int dsti = 1; + + bool fschecks = true; + + while (src[srci] != '\0') + { + // Skip slashes. + while (src[srci] == '/') + srci++; + int tmpi = srci; + // Find next slash. + while (src[srci] != '/' && src[srci] != '\0') + srci++; + if (srci == tmpi) + // We hit the end. + break; + len = srci - tmpi; + + // Handle "." and "..". + if (len == 1 && src[tmpi] == '.') + continue; + if (len == 2 && src[tmpi] == '.' && src[tmpi + 1] == '.') + { + while (dsti > 1 && dst[dsti - 1] != '/') + dsti--; + if (dsti != 1) + dsti--; + // Reenable filesystem checking if disabled, as we might + // have reversed over whatever caused the problem before. + // At least one proprietary JVM has inconsistencies because + // it does not do this. + fschecks = true; + continue; + } + + // Handle real path components. + dst = maybeGrowBuf (dst, &dstl, dsti + (dsti > 1 ? 1 : 0) + len + 1); + int dsti_save = dsti; + if (dsti > 1) + dst[dsti++] = '/'; + strncpy (&dst[dsti], &src[tmpi], len); + dsti += len; + if (fschecks == false) + continue; + +#if defined (HAVE_LSTAT) && defined (HAVE_READLINK) + struct stat sb; + dst[dsti] = '\0'; + if (::lstat (dst, &sb) == 0) + { + if (S_ISLNK (sb.st_mode)) + { + int tmpl = CHUNKSIZ; + char *tmp = (char *) _Jv_Malloc (tmpl); + + while (1) + { + tmpi = ::readlink (dst, tmp, tmpl); + if (tmpi < 1) + { + _Jv_Free (src); + _Jv_Free (dst); + _Jv_Free (tmp); + throw new IOException ( + JvNewStringLatin1 ("readlink failed")); + } + if (tmpi < tmpl) + break; + tmpl += CHUNKSIZ; + tmp = (char *) _Jv_Realloc (tmp, tmpl); + } + + // Prepend the link's path to src. + tmp = maybeGrowBuf (tmp, &tmpl, tmpi + strlen (&src[srci]) + 1); + strcpy(&tmp[tmpi], &src[srci]); + _Jv_Free (src); + src = tmp; + srcl = tmpl; + srci = 0; + + // Either replace or append dst depending on whether the + // link is relative or absolute. + dsti = src[0] == '/' ? 1 : dsti_save; + } + } + else + { + // Something doesn't exist, or we don't have permission to + // read it, or a previous path component is a directory, or + // a symlink is looped. Whatever, we can't check the + // filesystem any more. + fschecks = false; + } +#endif // HAVE_LSTAT && HAVE_READLINK + } + dst[dsti] = '\0'; + + // FIXME: what encoding to assume for file names? This affects many + // calls. + path = JvNewStringUTF (dst); + _Jv_Free (src); + _Jv_Free (dst); + return path; +} + +jboolean +java::io::File::isAbsolute (void) +{ + return path->length() > 0 && path->charAt(0) == '/'; +} + +jobjectArray +java::io::File::performList (java::io::FilenameFilter *filter, + java::io::FileFilter *fileFilter, + java::lang::Class *result_type) +{ + /* Some systems have dirent.h, but no directory reading functions like + opendir. */ +#if defined(HAVE_DIRENT_H) && defined(HAVE_OPENDIR) + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + + DIR *dir = opendir (buf); + if (! dir) + return NULL; + + java::util::ArrayList *list = new java::util::ArrayList (); + struct dirent *d; +#if defined(HAVE_READDIR_R) && defined(_POSIX_PTHREAD_SEMANTICS) + int name_max = pathconf (buf, _PC_NAME_MAX); + char dbuf[sizeof (struct dirent) + name_max + 1]; + while (readdir_r (dir, (struct dirent *) dbuf, &d) == 0 && d != NULL) +#else /* HAVE_READDIR_R */ + while ((d = readdir (dir)) != NULL) +#endif /* HAVE_READDIR_R */ + { + // Omit "." and "..". + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' + || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + + jstring name = JvNewStringUTF (d->d_name); + if (filter && ! filter->accept(this, name)) + continue; + + if (result_type == &java::io::File::class$) + { + java::io::File *file = new java::io::File (this, name); + if (fileFilter && ! fileFilter->accept(file)) + continue; + + list->add(file); + } + else + list->add(name); + } + + closedir (dir); + + jobjectArray ret = JvNewObjectArray (list->size(), result_type, NULL); + list->toArray(ret); + return ret; +#else /* HAVE_DIRENT_H && HAVE_OPENDIR */ + return NULL; +#endif /* HAVE_DIRENT_H && HAVE_OPENDIR */ +} + +jboolean +java::io::File::performMkdir (void) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + +#ifdef HAVE_MKDIR + return ::mkdir (buf, 0755) == 0; +#else + return false; +#endif +} + +jboolean +java::io::File::performSetReadOnly (void) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + +#if defined (HAVE_STAT) && defined (HAVE_CHMOD) + struct stat sb; + if (::stat (buf, &sb)) + return false; + + if (::chmod(buf, sb.st_mode & 0555)) + return false; + return true; +#else + return false; +#endif +} + +JArray< ::java::io::File *>* +java::io::File::performListRoots () +{ + ::java::io::File *f = new ::java::io::File (JvNewStringLatin1 ("/")); + JArray<java::io::File *> *unixroot + = reinterpret_cast <JArray<java::io::File *>*> + (JvNewObjectArray (1, &java::io::File::class$, f)); + elements (unixroot) [0] = f; + return unixroot; +} + +jboolean +java::io::File::performRenameTo (File *dest) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + char *buf2 + = (char *) __builtin_alloca (JvGetStringUTFLength (dest->path) + 1); + total = JvGetStringUTFRegion (dest->path, 0, dest->path->length(), buf2); + buf2[total] = '\0'; + +#ifdef HAVE_RENAME + return ::rename (buf, buf2) == 0; +#else + return false; +#endif +} + +jboolean +java::io::File::performSetLastModified (jlong time) +{ +#ifdef HAVE_UTIME + utimbuf tb; + + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + + tb.actime = time / 1000; + tb.modtime = time / 1000; + return (::utime (buf, &tb) == 0); +#else + return false; +#endif +} + +jboolean +java::io::File::performCreate (void) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + + int fd = ::open (buf, O_CREAT | O_EXCL, 0644); + + if (fd < 0) + { + if (errno == EEXIST) + return false; + throw new IOException (JvNewStringLatin1 (strerror (errno))); + } + else + { + ::close (fd); + return true; + } +} + +jboolean +java::io::File::performDelete (void) +{ + char *buf = (char *) __builtin_alloca (JvGetStringUTFLength (path) + 1); + jsize total = JvGetStringUTFRegion (path, 0, path->length(), buf); + buf[total] = '\0'; + +#ifdef HAVE_UNLINK +#ifdef HAVE_RMDIR + if (! ::rmdir (buf)) + return true; + if (errno == ENOTDIR) +#endif // HAVE_RMDIR + return ::unlink (buf) == 0; +#endif // HAVE_UNLINK + return false; +} + +void +java::io::File::init_native () +{ + maxPathLen = MAXPATHLEN; + caseSensitive = true; +} diff --git a/gcc-4.2.1/libjava/java/io/natFileWin32.cc b/gcc-4.2.1/libjava/java/io/natFileWin32.cc new file mode 100644 index 000000000..cff86dda7 --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/natFileWin32.cc @@ -0,0 +1,351 @@ +// natFileWin32.cc - Native part of File class for Win32. + +/* Copyright (C) 1998, 1999, 2002, 2003 Free Software Foundation, Inc. + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <stdio.h> +#include <string.h> + +#undef STRICT + +#include <java/io/File.h> +#include <java/io/IOException.h> +#include <java/util/Vector.h> +#include <java/lang/String.h> +#include <java/io/FilenameFilter.h> +#include <java/io/FileFilter.h> +#include <java/lang/System.h> + +// Java timestamps are milliseconds since the UNIX epoch (00:00:00 UTC on +// January 1, 1970) while Win32 file-times are 100-nanosecond intervals +// since the Win32 epoch (00:00:00 UTC on January 1, 1601). The following +// constant represents the number of milliseconds to be added to a +// Java timestamp to base it on the Win32 epoch. +// +// There were 369 years between 1601 and 1970, including 89 leap years +// (since 1700, 1800 and 1900 were not leap years): +// +// (89*366 + 280*365) days * 86400 seconds/day = 11644473600 seconds +// +#define WIN32_EPOCH_MILLIS 11644473600000LL + +jboolean +java::io::File::_access (jint query) +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + JvAssert (query == READ || query == WRITE || query == EXISTS); + + // FIXME: Is it possible to differentiate between existing and reading? + // If the file exists but cannot be read because of the secuirty attributes + // on an NTFS disk this wont work (it reports it can be read but cant) + // Could we use something from the security API? + DWORD attributes = GetFileAttributes (canon); + if ((query == EXISTS) || (query == READ)) + return (attributes == 0xffffffff) ? false : true; + else + return ((attributes != 0xffffffff) && + ((attributes & FILE_ATTRIBUTE_READONLY) == 0)) ? true : false; +} + +jboolean +java::io::File::_stat (jint query) +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + JvAssert (query == DIRECTORY || query == ISFILE); + + DWORD attributes = GetFileAttributes (canon); + if (attributes == 0xffffffff) + return false; + + if (query == DIRECTORY) + return attributes & FILE_ATTRIBUTE_DIRECTORY ? true : false; + else + return attributes & FILE_ATTRIBUTE_DIRECTORY ? false : true; +} + +jlong +java::io::File::attr (jint query) +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + JvAssert (query == MODIFIED || query == LENGTH); + + WIN32_FIND_DATA info; + HANDLE sHandle; + if ( ( sHandle = FindFirstFile( canon, &info)) == INVALID_HANDLE_VALUE) + return 0; + + FindClose( sHandle); + + if (query == LENGTH) + return ((long long)info.nFileSizeHigh) << 32 + | (unsigned long long)info.nFileSizeLow; + else + { + // The file time as returned by Windows is in terms of the number + // of 100-nanosecond intervals since 00:00:00 UTC, January 1, 1601. + return (((((long long)info.ftLastWriteTime.dwHighDateTime) << 32) + | ((unsigned long long)info.ftLastWriteTime.dwLowDateTime)) + - WIN32_EPOCH_MILLIS*10000LL) / 10000LL; + } +} + +jstring +java::io::File::getCanonicalPath (void) +{ + JV_TEMP_STRING_WIN32 (cpath, path); + + // If the filename is blank, use the current directory. + LPCTSTR thepath = cpath.buf(); + if (*thepath == 0) + thepath = _T("."); + + LPTSTR unused; + TCHAR buf2[MAX_PATH]; + if(!GetFullPathName(thepath, MAX_PATH, buf2, &unused)) + throw new IOException (JvNewStringLatin1 ("GetFullPathName failed")); + + return _Jv_Win32NewString (buf2); +} + +jboolean +java::io::File::isAbsolute (void) +{ + // See if the path represents a Windows UNC network path. + if (path->length () > 2 + && (path->charAt (0) == '\\') && (path->charAt (1) == '\\')) + return true; + + // Note that the path is not an absolute path even if it starts with + // a '/' or a '\' because it lacks a drive specifier. + + if (path->length() < 3) + return false; + // Hard-code A-Za-z because Windows (I think) can't use non-ASCII + // letters as drive names. + if ((path->charAt(0) < 'a' || path->charAt(0) > 'z') + && (path->charAt(0) < 'A' || path->charAt(0) > 'Z')) + return false; + return (path->charAt(1) == ':' + && (path->charAt(2) == '/' || path->charAt(2) == '\\')); +} + +void java::io::File::init_native () +{ + maxPathLen = MAX_PATH; + caseSensitive = false; +} + +jobjectArray +java::io::File::performList (java::io::FilenameFilter *filter, + java::io::FileFilter *fileFilter, + java::lang::Class *clazz) +{ + jstring canon = getCanonicalPath(); + if (! canon) + return NULL; + + int len = canon->length(); + TCHAR buf[len + 5]; + + JV_TEMP_STRING_WIN32(canonstr, canon); + + _tcscpy(buf, canonstr); + if (buf[len - 1] == _T('\\')) + _tcscpy (&buf[len], _T("*.*")); + else + _tcscpy (&buf[len], _T("\\*.*")); + + WIN32_FIND_DATA data; + HANDLE handle = FindFirstFile (buf, &data); + if (handle == INVALID_HANDLE_VALUE) + return NULL; + + java::util::Vector *vec = new java::util::Vector (); + + do + { + if (_tcscmp (data.cFileName, _T(".")) && + _tcscmp (data.cFileName, _T(".."))) + { + jstring name = _Jv_Win32NewString (data.cFileName); + + if (filter && !filter->accept(this, name)) + continue; + if (clazz == &java::io::File::class$) + { + java::io::File *file = new java::io::File (this, name); + if (fileFilter && !fileFilter->accept(file)) + continue; + vec->addElement (file); + } + else + vec->addElement (name); + } + } + while (FindNextFile (handle, &data)); + + if (GetLastError () != ERROR_NO_MORE_FILES) + return NULL; + + FindClose (handle); + + jobjectArray ret = JvNewObjectArray (vec->size(), clazz, NULL); + vec->copyInto (ret); + return ret; +} + +jboolean +java::io::File::performMkdir (void) +{ + JV_TEMP_STRING_WIN32 (cpath, path); + return (CreateDirectory(cpath, NULL)) ? true : false; +} + +jboolean +java::io::File::performRenameTo (File *dest) +{ + JV_TEMP_STRING_WIN32 (pathFrom, path); + JV_TEMP_STRING_WIN32 (pathTo, dest->path); + return (MoveFile(pathFrom, pathTo)) ? true : false; +} + +jboolean +java::io::File::performDelete () +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + DWORD attributes = GetFileAttributes (canon); + if (attributes == 0xffffffff) + return false; + + if (attributes & FILE_ATTRIBUTE_DIRECTORY) + return (RemoveDirectory (canon)) ? true : false; + else + return (DeleteFile (canon)) ? true : false; +} + +jboolean java::io::File::performCreate (void) +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + HANDLE h = CreateFile (canon, 0, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (h != INVALID_HANDLE_VALUE) + { + CloseHandle (h); + return true; + } + else + { + if (GetLastError () == ERROR_ALREADY_EXISTS) + return false; + else + throw new IOException (JvNewStringLatin1 ("CreateFile failed")); + } +} + +jboolean java::io::File::performSetReadOnly () +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + DWORD attrs = GetFileAttributes (canon); + if (attrs != INVALID_FILE_ATTRIBUTES) + { + if (SetFileAttributes (canon, attrs | FILE_ATTRIBUTE_READONLY) != 0) + return true; + else + return false; + } + else + return false; +} + +jboolean java::io::File::performSetLastModified (jlong time) +{ + JV_TEMP_STRING_WIN32 (canon, getCanonicalPath()); + if (!canon) + return false; + + FILETIME modTime; + long long mTime100ns = ((long long) time /* Ha! */ + + WIN32_EPOCH_MILLIS) * 10000LL; + + modTime.dwLowDateTime = (DWORD) mTime100ns; + modTime.dwHighDateTime = (DWORD) (mTime100ns >> 32); + + jboolean retVal = false; + HANDLE h = CreateFile (canon, FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, NULL); + + if (h != INVALID_HANDLE_VALUE) + { + if (SetFileTime (h, NULL, &modTime, &modTime) != 0) + retVal = true; + + CloseHandle (h); + } + + return retVal; +} + +JArray<java::io::File*>* java::io::File::performListRoots () +{ + DWORD drivesBitmap = GetLogicalDrives (); + DWORD mask; + + // Possible drive letters are from ASCII 'A'-'Z'. + int numDrives = 0; + mask = 1; + for (int i = 0; i < 26; i++) + { + if ((drivesBitmap & mask) != 0) + numDrives++; + mask <<= 1; + } + + JArray<java::io::File *> *roots + = reinterpret_cast <JArray<java::io::File *>*> + (JvNewObjectArray (numDrives, &java::io::File::class$, NULL)); + + ::java::io::File **rootsArray = elements (roots); + + char aDriveRoot[] = {'A', ':', '\\', '\0'}; + mask = 1; + for (int i = 0, j = 0; i < 26; i++) + { + if ((drivesBitmap & mask) != 0) + { + rootsArray[j] + = new ::java::io::File (JvNewStringLatin1 (aDriveRoot)); + j++; + } + mask <<= 1; + aDriveRoot[0]++; + } + + return roots; +} diff --git a/gcc-4.2.1/libjava/java/io/natObjectInputStream.cc b/gcc-4.2.1/libjava/java/io/natObjectInputStream.cc new file mode 100644 index 000000000..2d1a55665 --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/natObjectInputStream.cc @@ -0,0 +1,80 @@ +// natObjectInputStream.cc - Native part of ObjectInputStream class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2005 Free Software Foundation + + This ObjectInputStream is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the ObjectInputStream "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <gcj/method.h> + +#include <java/io/ObjectInputStream$GetField.h> +#include <java/io/ObjectInputStream.h> +#include <java/io/IOException.h> +#include <java/lang/Class.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/reflect/Method.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/SecurityManager.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/reflect/Method.h> +#include <java-stack.h> + +#ifdef DEBUG +#include <java/lang/System.h> +#include <java/io/PrintStream.h> +#endif + +jobject +java::io::ObjectInputStream::allocateObject (jclass klass, jclass, + ::java::lang::reflect::Constructor *ctr) +{ + jobject obj = NULL; + using namespace java::lang::reflect; + + try + { + JvAssert (klass && ! klass->isArray ()); + if (klass->isInterface() || Modifier::isAbstract(klass->getModifiers())) + obj = NULL; + else + { + obj = _Jv_AllocObject (klass); + } + } + catch (jthrowable t) + { + return NULL; + } + + jmethodID meth = _Jv_FromReflectedConstructor (ctr); + + // This is a bit inefficient, and a bit of a hack, since we don't + // actually use the Method and since what is returned isn't + // technically a Method. We can't use Method.invoke as it looks up + // the declared method. + JArray<jclass> *arg_types + = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$, + NULL); + + // We lie about this being a constructor. If we put `true' here + // then _Jv_CallAnyMethodA would try to allocate the object for us. + _Jv_CallAnyMethodA (obj, JvPrimClass (void), meth, false, arg_types, NULL); + + return obj; +} + +java::lang::ClassLoader * +java::io::ObjectInputStream::currentLoader () +{ + jclass caller = _Jv_StackTrace::GetCallingClass (&ObjectInputStream::class$); + if (caller) + return caller->getClassLoaderInternal(); + return NULL; +} diff --git a/gcc-4.2.1/libjava/java/io/natVMObjectStreamClass.cc b/gcc-4.2.1/libjava/java/io/natVMObjectStreamClass.cc new file mode 100644 index 000000000..847b540f0 --- /dev/null +++ b/gcc-4.2.1/libjava/java/io/natVMObjectStreamClass.cc @@ -0,0 +1,87 @@ +// natVMObjectStreamClass.cc - Native part of VMObjectStreamClass class. + +/* Copyright (C) 2003 Free Software Foundation + + This VMObjectStreamClass is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the ObjectInputStream "LIBGCJ_LICENSE" for +details. */ + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/io/VMObjectStreamClass.h> +#include <java/lang/Class.h> +#include <java/lang/reflect/Field.h> + +using namespace java::lang::reflect; + +jboolean +java::io::VMObjectStreamClass::hasClassInitializer (jclass klass) +{ + if (klass->isPrimitive()) + return false; + _Jv_Method *meth = _Jv_GetMethodLocal(klass, gcj::clinit_name, + gcj::void_signature); + return (meth != NULL); +} + +void +java::io::VMObjectStreamClass::setDoubleNative (Field *f, jobject obj, + jdouble val) +{ + f->setDouble (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setFloatNative (Field *f, jobject obj, + jfloat val) +{ + f->setFloat (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setLongNative (Field *f, jobject obj, jlong val) +{ + f->setLong (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setIntNative (Field *f, jobject obj, jint val) +{ + f->setInt (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setShortNative (Field *f, jobject obj, + jshort val) +{ + f->setShort (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setCharNative (Field *f, jobject obj, jchar val) +{ + f->setChar (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setByteNative (Field *f, jobject obj, jbyte val) +{ + f->setByte (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setBooleanNative (Field *f, jobject obj, + jboolean val) +{ + f->setBoolean (NULL, obj, val, false); +} + +void +java::io::VMObjectStreamClass::setObjectNative (Field *f, jobject obj, + jobject val) +{ + f->set (NULL, obj, val, f->getType(), false); +} diff --git a/gcc-4.2.1/libjava/java/lang/Character.java b/gcc-4.2.1/libjava/java/lang/Character.java new file mode 100644 index 000000000..ec6d2a4af --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Character.java @@ -0,0 +1,3867 @@ +/* java.lang.Character -- Wrapper class for char, and Unicode subsets + Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +/* + * Note: This class must not be merged with Classpath. Gcj uses C-style + * arrays (see include/java-chartables.h) to store the Unicode character + * database, whereas Classpath uses Java objects (char[] extracted from + * String constants) in gnu.java.lang.CharData. Gcj's approach is more + * efficient, because there is no vtable or data relocation to worry about. + * However, despite the difference in the database interface, the two + * versions share identical algorithms. + */ + +package java.lang; + +import java.io.Serializable; +import java.text.Collator; +import java.util.Locale; + +/** + * Wrapper class for the primitive char data type. In addition, this class + * allows one to retrieve property information and perform transformations + * on the 57,707 defined characters in the Unicode Standard, Version 3.0.0. + * java.lang.Character is designed to be very dynamic, and as such, it + * retrieves information on the Unicode character set from a separate + * database, gnu.java.lang.CharData, which can be easily upgraded. + * + * <p>For predicates, boundaries are used to describe + * the set of characters for which the method will return true. + * This syntax uses fairly normal regular expression notation. + * See 5.13 of the Unicode Standard, Version 3.0, for the + * boundary specification. + * + * <p>See <a href="http://www.unicode.org">http://www.unicode.org</a> + * for more information on the Unicode Standard. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Paul N. Fisher + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status updated to 1.4 + */ +public final class Character implements Serializable, Comparable +{ + /** + * A subset of Unicode blocks. + * + * @author Paul N. Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.2 + */ + public static class Subset + { + /** The name of the subset. */ + private final String name; + + /** + * Construct a new subset of characters. + * + * @param name the name of the subset + * @throws NullPointerException if name is null + */ + protected Subset(String name) + { + // Note that name.toString() is name, unless name was null. + this.name = name.toString(); + } + + /** + * Compares two Subsets for equality. This is <code>final</code>, and + * restricts the comparison on the <code>==</code> operator, so it returns + * true only for the same object. + * + * @param o the object to compare + * @return true if o is this + */ + public final boolean equals(Object o) + { + return o == this; + } + + /** + * Makes the original hashCode of Object final, to be consistent with + * equals. + * + * @return the hash code for this object + */ + public final int hashCode() + { + return super.hashCode(); + } + + /** + * Returns the name of the subset. + * + * @return the name + */ + public final String toString() + { + return name; + } + } // class Subset + + /** + * A family of character subsets in the Unicode specification. A character + * is in at most one of these blocks. + * + * This inner class was generated automatically from + * <code>libjava/gnu/gcj/convert/Blocks-3.txt</code>, by some perl scripts. + * This Unicode definition file can be found on the + * <a href="http://www.unicode.org">http://www.unicode.org</a> website. + * JDK 1.4 uses Unicode version 3.0.0. + * + * @author scripts/unicode-blocks.pl (written by Eric Blake) + * @since 1.2 + */ + public static final class UnicodeBlock extends Subset + { + /** The start of the subset. */ + private final int start; + + /** The end of the subset. */ + private final int end; + + /** The canonical name of the block according to the Unicode standard. */ + private final String canonicalName; + + /** Constants for the <code>forName()</code> method */ + private static final int CANONICAL_NAME = 0; + private static final int NO_SPACES_NAME = 1; + private static final int CONSTANT_NAME = 2; + + /** + * Constructor for strictly defined blocks. + * + * @param start the start character of the range + * @param end the end character of the range + * @param name the block name + */ + private UnicodeBlock(int start, int end, String name, + String canonicalName) + { + super(name); + this.start = start; + this.end = end; + this.canonicalName = canonicalName; + } + + /** + * Returns the Unicode character block which a character belongs to. + * <strong>Note</strong>: This method does not support the use of + * supplementary characters. For such support, <code>of(int)</code> + * should be used instead. + * + * @param ch the character to look up + * @return the set it belongs to, or null if it is not in one + */ + public static UnicodeBlock of(char ch) + { + return of((int) ch); + } + + /** + * Returns the Unicode character block which a code point belongs to. + * + * @param codePoint the character to look up + * @return the set it belongs to, or null if it is not in one. + * @throws IllegalArgumentException if the specified code point is + * invalid. + * @since 1.5 + */ + public static UnicodeBlock of(int codePoint) + { + if (codePoint > MAX_CODE_POINT) + throw new IllegalArgumentException("The supplied integer value is " + + "too large to be a codepoint."); + // Simple binary search for the correct block. + int low = 0; + int hi = sets.length - 1; + while (low <= hi) + { + int mid = (low + hi) >> 1; + UnicodeBlock b = sets[mid]; + if (codePoint < b.start) + hi = mid - 1; + else if (codePoint > b.end) + low = mid + 1; + else + return b; + } + return null; + } + + /** + * <p> + * Returns the <code>UnicodeBlock</code> with the given name, as defined + * by the Unicode standard. The version of Unicode in use is defined by + * the <code>Character</code> class, and the names are given in the + * <code>Blocks-<version>.txt</code> file corresponding to that version. + * The name may be specified in one of three ways: + * </p> + * <ol> + * <li>The canonical, human-readable name used by the Unicode standard. + * This is the name with all spaces and hyphens retained. For example, + * `Basic Latin' retrieves the block, UnicodeBlock.BASIC_LATIN.</li> + * <li>The canonical name with all spaces removed e.g. `BasicLatin'.</li> + * <li>The name used for the constants specified by this class, which + * is the canonical name with all spaces and hyphens replaced with + * underscores e.g. `BASIC_LATIN'</li> + * </ol> + * <p> + * The names are compared case-insensitively using the case comparison + * associated with the U.S. English locale. The method recognises the + * previous names used for blocks as well as the current ones. At + * present, this simply means that the deprecated `SURROGATES_AREA' + * will be recognised by this method (the <code>of()</code> methods + * only return one of the three new surrogate blocks). + * </p> + * + * @param blockName the name of the block to look up. + * @return the specified block. + * @throws NullPointerException if the <code>blockName</code> is + * <code>null</code>. + * @throws IllegalArgumentException if the name does not match any Unicode + * block. + * @since 1.5 + */ + public static final UnicodeBlock forName(String blockName) + { + int type; + if (blockName.indexOf(' ') != -1) + type = CANONICAL_NAME; + else if (blockName.indexOf('_') != -1) + type = CONSTANT_NAME; + else + type = NO_SPACES_NAME; + Collator usCollator = Collator.getInstance(Locale.US); + usCollator.setStrength(Collator.PRIMARY); + /* Special case for deprecated blocks not in sets */ + switch (type) + { + case CANONICAL_NAME: + if (usCollator.compare(blockName, "Surrogates Area") == 0) + return SURROGATES_AREA; + break; + case NO_SPACES_NAME: + if (usCollator.compare(blockName, "SurrogatesArea") == 0) + return SURROGATES_AREA; + break; + case CONSTANT_NAME: + if (usCollator.compare(blockName, "SURROGATES_AREA") == 0) + return SURROGATES_AREA; + break; + } + /* Other cases */ + int setLength = sets.length; + switch (type) + { + case CANONICAL_NAME: + for (int i = 0; i < setLength; i++) + { + UnicodeBlock block = sets[i]; + if (usCollator.compare(blockName, block.canonicalName) == 0) + return block; + } + break; + case NO_SPACES_NAME: + for (int i = 0; i < setLength; i++) + { + UnicodeBlock block = sets[i]; + String nsName = block.canonicalName.replaceAll(" ",""); + if (usCollator.compare(blockName, nsName) == 0) + return block; + } + break; + case CONSTANT_NAME: + for (int i = 0; i < setLength; i++) + { + UnicodeBlock block = sets[i]; + if (usCollator.compare(blockName, block.toString()) == 0) + return block; + } + break; + } + throw new IllegalArgumentException("No Unicode block found for " + + blockName + "."); + } + + /** + * Basic Latin. + * 0x0000 - 0x007F. + */ + public static final UnicodeBlock BASIC_LATIN + = new UnicodeBlock(0x0000, 0x007F, + "BASIC_LATIN", + "Basic Latin"); + + /** + * Latin-1 Supplement. + * 0x0080 - 0x00FF. + */ + public static final UnicodeBlock LATIN_1_SUPPLEMENT + = new UnicodeBlock(0x0080, 0x00FF, + "LATIN_1_SUPPLEMENT", + "Latin-1 Supplement"); + + /** + * Latin Extended-A. + * 0x0100 - 0x017F. + */ + public static final UnicodeBlock LATIN_EXTENDED_A + = new UnicodeBlock(0x0100, 0x017F, + "LATIN_EXTENDED_A", + "Latin Extended-A"); + + /** + * Latin Extended-B. + * 0x0180 - 0x024F. + */ + public static final UnicodeBlock LATIN_EXTENDED_B + = new UnicodeBlock(0x0180, 0x024F, + "LATIN_EXTENDED_B", + "Latin Extended-B"); + + /** + * IPA Extensions. + * 0x0250 - 0x02AF. + */ + public static final UnicodeBlock IPA_EXTENSIONS + = new UnicodeBlock(0x0250, 0x02AF, + "IPA_EXTENSIONS", + "IPA Extensions"); + + /** + * Spacing Modifier Letters. + * 0x02B0 - 0x02FF. + */ + public static final UnicodeBlock SPACING_MODIFIER_LETTERS + = new UnicodeBlock(0x02B0, 0x02FF, + "SPACING_MODIFIER_LETTERS", + "Spacing Modifier Letters"); + + /** + * Combining Diacritical Marks. + * 0x0300 - 0x036F. + */ + public static final UnicodeBlock COMBINING_DIACRITICAL_MARKS + = new UnicodeBlock(0x0300, 0x036F, + "COMBINING_DIACRITICAL_MARKS", + "Combining Diacritical Marks"); + + /** + * Greek. + * 0x0370 - 0x03FF. + */ + public static final UnicodeBlock GREEK + = new UnicodeBlock(0x0370, 0x03FF, + "GREEK", + "Greek"); + + /** + * Cyrillic. + * 0x0400 - 0x04FF. + */ + public static final UnicodeBlock CYRILLIC + = new UnicodeBlock(0x0400, 0x04FF, + "CYRILLIC", + "Cyrillic"); + + /** + * Cyrillic Supplementary. + * 0x0500 - 0x052F. + * @since 1.5 + */ + public static final UnicodeBlock CYRILLIC_SUPPLEMENTARY + = new UnicodeBlock(0x0500, 0x052F, + "CYRILLIC_SUPPLEMENTARY", + "Cyrillic Supplementary"); + + /** + * Armenian. + * 0x0530 - 0x058F. + */ + public static final UnicodeBlock ARMENIAN + = new UnicodeBlock(0x0530, 0x058F, + "ARMENIAN", + "Armenian"); + + /** + * Hebrew. + * 0x0590 - 0x05FF. + */ + public static final UnicodeBlock HEBREW + = new UnicodeBlock(0x0590, 0x05FF, + "HEBREW", + "Hebrew"); + + /** + * Arabic. + * 0x0600 - 0x06FF. + */ + public static final UnicodeBlock ARABIC + = new UnicodeBlock(0x0600, 0x06FF, + "ARABIC", + "Arabic"); + + /** + * Syriac. + * 0x0700 - 0x074F. + * @since 1.4 + */ + public static final UnicodeBlock SYRIAC + = new UnicodeBlock(0x0700, 0x074F, + "SYRIAC", + "Syriac"); + + /** + * Thaana. + * 0x0780 - 0x07BF. + * @since 1.4 + */ + public static final UnicodeBlock THAANA + = new UnicodeBlock(0x0780, 0x07BF, + "THAANA", + "Thaana"); + + /** + * Devanagari. + * 0x0900 - 0x097F. + */ + public static final UnicodeBlock DEVANAGARI + = new UnicodeBlock(0x0900, 0x097F, + "DEVANAGARI", + "Devanagari"); + + /** + * Bengali. + * 0x0980 - 0x09FF. + */ + public static final UnicodeBlock BENGALI + = new UnicodeBlock(0x0980, 0x09FF, + "BENGALI", + "Bengali"); + + /** + * Gurmukhi. + * 0x0A00 - 0x0A7F. + */ + public static final UnicodeBlock GURMUKHI + = new UnicodeBlock(0x0A00, 0x0A7F, + "GURMUKHI", + "Gurmukhi"); + + /** + * Gujarati. + * 0x0A80 - 0x0AFF. + */ + public static final UnicodeBlock GUJARATI + = new UnicodeBlock(0x0A80, 0x0AFF, + "GUJARATI", + "Gujarati"); + + /** + * Oriya. + * 0x0B00 - 0x0B7F. + */ + public static final UnicodeBlock ORIYA + = new UnicodeBlock(0x0B00, 0x0B7F, + "ORIYA", + "Oriya"); + + /** + * Tamil. + * 0x0B80 - 0x0BFF. + */ + public static final UnicodeBlock TAMIL + = new UnicodeBlock(0x0B80, 0x0BFF, + "TAMIL", + "Tamil"); + + /** + * Telugu. + * 0x0C00 - 0x0C7F. + */ + public static final UnicodeBlock TELUGU + = new UnicodeBlock(0x0C00, 0x0C7F, + "TELUGU", + "Telugu"); + + /** + * Kannada. + * 0x0C80 - 0x0CFF. + */ + public static final UnicodeBlock KANNADA + = new UnicodeBlock(0x0C80, 0x0CFF, + "KANNADA", + "Kannada"); + + /** + * Malayalam. + * 0x0D00 - 0x0D7F. + */ + public static final UnicodeBlock MALAYALAM + = new UnicodeBlock(0x0D00, 0x0D7F, + "MALAYALAM", + "Malayalam"); + + /** + * Sinhala. + * 0x0D80 - 0x0DFF. + * @since 1.4 + */ + public static final UnicodeBlock SINHALA + = new UnicodeBlock(0x0D80, 0x0DFF, + "SINHALA", + "Sinhala"); + + /** + * Thai. + * 0x0E00 - 0x0E7F. + */ + public static final UnicodeBlock THAI + = new UnicodeBlock(0x0E00, 0x0E7F, + "THAI", + "Thai"); + + /** + * Lao. + * 0x0E80 - 0x0EFF. + */ + public static final UnicodeBlock LAO + = new UnicodeBlock(0x0E80, 0x0EFF, + "LAO", + "Lao"); + + /** + * Tibetan. + * 0x0F00 - 0x0FFF. + */ + public static final UnicodeBlock TIBETAN + = new UnicodeBlock(0x0F00, 0x0FFF, + "TIBETAN", + "Tibetan"); + + /** + * Myanmar. + * 0x1000 - 0x109F. + * @since 1.4 + */ + public static final UnicodeBlock MYANMAR + = new UnicodeBlock(0x1000, 0x109F, + "MYANMAR", + "Myanmar"); + + /** + * Georgian. + * 0x10A0 - 0x10FF. + */ + public static final UnicodeBlock GEORGIAN + = new UnicodeBlock(0x10A0, 0x10FF, + "GEORGIAN", + "Georgian"); + + /** + * Hangul Jamo. + * 0x1100 - 0x11FF. + */ + public static final UnicodeBlock HANGUL_JAMO + = new UnicodeBlock(0x1100, 0x11FF, + "HANGUL_JAMO", + "Hangul Jamo"); + + /** + * Ethiopic. + * 0x1200 - 0x137F. + * @since 1.4 + */ + public static final UnicodeBlock ETHIOPIC + = new UnicodeBlock(0x1200, 0x137F, + "ETHIOPIC", + "Ethiopic"); + + /** + * Cherokee. + * 0x13A0 - 0x13FF. + * @since 1.4 + */ + public static final UnicodeBlock CHEROKEE + = new UnicodeBlock(0x13A0, 0x13FF, + "CHEROKEE", + "Cherokee"); + + /** + * Unified Canadian Aboriginal Syllabics. + * 0x1400 - 0x167F. + * @since 1.4 + */ + public static final UnicodeBlock UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS + = new UnicodeBlock(0x1400, 0x167F, + "UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS", + "Unified Canadian Aboriginal Syllabics"); + + /** + * Ogham. + * 0x1680 - 0x169F. + * @since 1.4 + */ + public static final UnicodeBlock OGHAM + = new UnicodeBlock(0x1680, 0x169F, + "OGHAM", + "Ogham"); + + /** + * Runic. + * 0x16A0 - 0x16FF. + * @since 1.4 + */ + public static final UnicodeBlock RUNIC + = new UnicodeBlock(0x16A0, 0x16FF, + "RUNIC", + "Runic"); + + /** + * Tagalog. + * 0x1700 - 0x171F. + * @since 1.5 + */ + public static final UnicodeBlock TAGALOG + = new UnicodeBlock(0x1700, 0x171F, + "TAGALOG", + "Tagalog"); + + /** + * Hanunoo. + * 0x1720 - 0x173F. + * @since 1.5 + */ + public static final UnicodeBlock HANUNOO + = new UnicodeBlock(0x1720, 0x173F, + "HANUNOO", + "Hanunoo"); + + /** + * Buhid. + * 0x1740 - 0x175F. + * @since 1.5 + */ + public static final UnicodeBlock BUHID + = new UnicodeBlock(0x1740, 0x175F, + "BUHID", + "Buhid"); + + /** + * Tagbanwa. + * 0x1760 - 0x177F. + * @since 1.5 + */ + public static final UnicodeBlock TAGBANWA + = new UnicodeBlock(0x1760, 0x177F, + "TAGBANWA", + "Tagbanwa"); + + /** + * Khmer. + * 0x1780 - 0x17FF. + * @since 1.4 + */ + public static final UnicodeBlock KHMER + = new UnicodeBlock(0x1780, 0x17FF, + "KHMER", + "Khmer"); + + /** + * Mongolian. + * 0x1800 - 0x18AF. + * @since 1.4 + */ + public static final UnicodeBlock MONGOLIAN + = new UnicodeBlock(0x1800, 0x18AF, + "MONGOLIAN", + "Mongolian"); + + /** + * Limbu. + * 0x1900 - 0x194F. + * @since 1.5 + */ + public static final UnicodeBlock LIMBU + = new UnicodeBlock(0x1900, 0x194F, + "LIMBU", + "Limbu"); + + /** + * Tai Le. + * 0x1950 - 0x197F. + * @since 1.5 + */ + public static final UnicodeBlock TAI_LE + = new UnicodeBlock(0x1950, 0x197F, + "TAI_LE", + "Tai Le"); + + /** + * Khmer Symbols. + * 0x19E0 - 0x19FF. + * @since 1.5 + */ + public static final UnicodeBlock KHMER_SYMBOLS + = new UnicodeBlock(0x19E0, 0x19FF, + "KHMER_SYMBOLS", + "Khmer Symbols"); + + /** + * Phonetic Extensions. + * 0x1D00 - 0x1D7F. + * @since 1.5 + */ + public static final UnicodeBlock PHONETIC_EXTENSIONS + = new UnicodeBlock(0x1D00, 0x1D7F, + "PHONETIC_EXTENSIONS", + "Phonetic Extensions"); + + /** + * Latin Extended Additional. + * 0x1E00 - 0x1EFF. + */ + public static final UnicodeBlock LATIN_EXTENDED_ADDITIONAL + = new UnicodeBlock(0x1E00, 0x1EFF, + "LATIN_EXTENDED_ADDITIONAL", + "Latin Extended Additional"); + + /** + * Greek Extended. + * 0x1F00 - 0x1FFF. + */ + public static final UnicodeBlock GREEK_EXTENDED + = new UnicodeBlock(0x1F00, 0x1FFF, + "GREEK_EXTENDED", + "Greek Extended"); + + /** + * General Punctuation. + * 0x2000 - 0x206F. + */ + public static final UnicodeBlock GENERAL_PUNCTUATION + = new UnicodeBlock(0x2000, 0x206F, + "GENERAL_PUNCTUATION", + "General Punctuation"); + + /** + * Superscripts and Subscripts. + * 0x2070 - 0x209F. + */ + public static final UnicodeBlock SUPERSCRIPTS_AND_SUBSCRIPTS + = new UnicodeBlock(0x2070, 0x209F, + "SUPERSCRIPTS_AND_SUBSCRIPTS", + "Superscripts and Subscripts"); + + /** + * Currency Symbols. + * 0x20A0 - 0x20CF. + */ + public static final UnicodeBlock CURRENCY_SYMBOLS + = new UnicodeBlock(0x20A0, 0x20CF, + "CURRENCY_SYMBOLS", + "Currency Symbols"); + + /** + * Combining Marks for Symbols. + * 0x20D0 - 0x20FF. + */ + public static final UnicodeBlock COMBINING_MARKS_FOR_SYMBOLS + = new UnicodeBlock(0x20D0, 0x20FF, + "COMBINING_MARKS_FOR_SYMBOLS", + "Combining Marks for Symbols"); + + /** + * Letterlike Symbols. + * 0x2100 - 0x214F. + */ + public static final UnicodeBlock LETTERLIKE_SYMBOLS + = new UnicodeBlock(0x2100, 0x214F, + "LETTERLIKE_SYMBOLS", + "Letterlike Symbols"); + + /** + * Number Forms. + * 0x2150 - 0x218F. + */ + public static final UnicodeBlock NUMBER_FORMS + = new UnicodeBlock(0x2150, 0x218F, + "NUMBER_FORMS", + "Number Forms"); + + /** + * Arrows. + * 0x2190 - 0x21FF. + */ + public static final UnicodeBlock ARROWS + = new UnicodeBlock(0x2190, 0x21FF, + "ARROWS", + "Arrows"); + + /** + * Mathematical Operators. + * 0x2200 - 0x22FF. + */ + public static final UnicodeBlock MATHEMATICAL_OPERATORS + = new UnicodeBlock(0x2200, 0x22FF, + "MATHEMATICAL_OPERATORS", + "Mathematical Operators"); + + /** + * Miscellaneous Technical. + * 0x2300 - 0x23FF. + */ + public static final UnicodeBlock MISCELLANEOUS_TECHNICAL + = new UnicodeBlock(0x2300, 0x23FF, + "MISCELLANEOUS_TECHNICAL", + "Miscellaneous Technical"); + + /** + * Control Pictures. + * 0x2400 - 0x243F. + */ + public static final UnicodeBlock CONTROL_PICTURES + = new UnicodeBlock(0x2400, 0x243F, + "CONTROL_PICTURES", + "Control Pictures"); + + /** + * Optical Character Recognition. + * 0x2440 - 0x245F. + */ + public static final UnicodeBlock OPTICAL_CHARACTER_RECOGNITION + = new UnicodeBlock(0x2440, 0x245F, + "OPTICAL_CHARACTER_RECOGNITION", + "Optical Character Recognition"); + + /** + * Enclosed Alphanumerics. + * 0x2460 - 0x24FF. + */ + public static final UnicodeBlock ENCLOSED_ALPHANUMERICS + = new UnicodeBlock(0x2460, 0x24FF, + "ENCLOSED_ALPHANUMERICS", + "Enclosed Alphanumerics"); + + /** + * Box Drawing. + * 0x2500 - 0x257F. + */ + public static final UnicodeBlock BOX_DRAWING + = new UnicodeBlock(0x2500, 0x257F, + "BOX_DRAWING", + "Box Drawing"); + + /** + * Block Elements. + * 0x2580 - 0x259F. + */ + public static final UnicodeBlock BLOCK_ELEMENTS + = new UnicodeBlock(0x2580, 0x259F, + "BLOCK_ELEMENTS", + "Block Elements"); + + /** + * Geometric Shapes. + * 0x25A0 - 0x25FF. + */ + public static final UnicodeBlock GEOMETRIC_SHAPES + = new UnicodeBlock(0x25A0, 0x25FF, + "GEOMETRIC_SHAPES", + "Geometric Shapes"); + + /** + * Miscellaneous Symbols. + * 0x2600 - 0x26FF. + */ + public static final UnicodeBlock MISCELLANEOUS_SYMBOLS + = new UnicodeBlock(0x2600, 0x26FF, + "MISCELLANEOUS_SYMBOLS", + "Miscellaneous Symbols"); + + /** + * Dingbats. + * 0x2700 - 0x27BF. + */ + public static final UnicodeBlock DINGBATS + = new UnicodeBlock(0x2700, 0x27BF, + "DINGBATS", + "Dingbats"); + + /** + * Miscellaneous Mathematical Symbols-A. + * 0x27C0 - 0x27EF. + * @since 1.5 + */ + public static final UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A + = new UnicodeBlock(0x27C0, 0x27EF, + "MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A", + "Miscellaneous Mathematical Symbols-A"); + + /** + * Supplemental Arrows-A. + * 0x27F0 - 0x27FF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTAL_ARROWS_A + = new UnicodeBlock(0x27F0, 0x27FF, + "SUPPLEMENTAL_ARROWS_A", + "Supplemental Arrows-A"); + + /** + * Braille Patterns. + * 0x2800 - 0x28FF. + * @since 1.4 + */ + public static final UnicodeBlock BRAILLE_PATTERNS + = new UnicodeBlock(0x2800, 0x28FF, + "BRAILLE_PATTERNS", + "Braille Patterns"); + + /** + * Supplemental Arrows-B. + * 0x2900 - 0x297F. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTAL_ARROWS_B + = new UnicodeBlock(0x2900, 0x297F, + "SUPPLEMENTAL_ARROWS_B", + "Supplemental Arrows-B"); + + /** + * Miscellaneous Mathematical Symbols-B. + * 0x2980 - 0x29FF. + * @since 1.5 + */ + public static final UnicodeBlock MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B + = new UnicodeBlock(0x2980, 0x29FF, + "MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B", + "Miscellaneous Mathematical Symbols-B"); + + /** + * Supplemental Mathematical Operators. + * 0x2A00 - 0x2AFF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTAL_MATHEMATICAL_OPERATORS + = new UnicodeBlock(0x2A00, 0x2AFF, + "SUPPLEMENTAL_MATHEMATICAL_OPERATORS", + "Supplemental Mathematical Operators"); + + /** + * Miscellaneous Symbols and Arrows. + * 0x2B00 - 0x2BFF. + * @since 1.5 + */ + public static final UnicodeBlock MISCELLANEOUS_SYMBOLS_AND_ARROWS + = new UnicodeBlock(0x2B00, 0x2BFF, + "MISCELLANEOUS_SYMBOLS_AND_ARROWS", + "Miscellaneous Symbols and Arrows"); + + /** + * CJK Radicals Supplement. + * 0x2E80 - 0x2EFF. + * @since 1.4 + */ + public static final UnicodeBlock CJK_RADICALS_SUPPLEMENT + = new UnicodeBlock(0x2E80, 0x2EFF, + "CJK_RADICALS_SUPPLEMENT", + "CJK Radicals Supplement"); + + /** + * Kangxi Radicals. + * 0x2F00 - 0x2FDF. + * @since 1.4 + */ + public static final UnicodeBlock KANGXI_RADICALS + = new UnicodeBlock(0x2F00, 0x2FDF, + "KANGXI_RADICALS", + "Kangxi Radicals"); + + /** + * Ideographic Description Characters. + * 0x2FF0 - 0x2FFF. + * @since 1.4 + */ + public static final UnicodeBlock IDEOGRAPHIC_DESCRIPTION_CHARACTERS + = new UnicodeBlock(0x2FF0, 0x2FFF, + "IDEOGRAPHIC_DESCRIPTION_CHARACTERS", + "Ideographic Description Characters"); + + /** + * CJK Symbols and Punctuation. + * 0x3000 - 0x303F. + */ + public static final UnicodeBlock CJK_SYMBOLS_AND_PUNCTUATION + = new UnicodeBlock(0x3000, 0x303F, + "CJK_SYMBOLS_AND_PUNCTUATION", + "CJK Symbols and Punctuation"); + + /** + * Hiragana. + * 0x3040 - 0x309F. + */ + public static final UnicodeBlock HIRAGANA + = new UnicodeBlock(0x3040, 0x309F, + "HIRAGANA", + "Hiragana"); + + /** + * Katakana. + * 0x30A0 - 0x30FF. + */ + public static final UnicodeBlock KATAKANA + = new UnicodeBlock(0x30A0, 0x30FF, + "KATAKANA", + "Katakana"); + + /** + * Bopomofo. + * 0x3100 - 0x312F. + */ + public static final UnicodeBlock BOPOMOFO + = new UnicodeBlock(0x3100, 0x312F, + "BOPOMOFO", + "Bopomofo"); + + /** + * Hangul Compatibility Jamo. + * 0x3130 - 0x318F. + */ + public static final UnicodeBlock HANGUL_COMPATIBILITY_JAMO + = new UnicodeBlock(0x3130, 0x318F, + "HANGUL_COMPATIBILITY_JAMO", + "Hangul Compatibility Jamo"); + + /** + * Kanbun. + * 0x3190 - 0x319F. + */ + public static final UnicodeBlock KANBUN + = new UnicodeBlock(0x3190, 0x319F, + "KANBUN", + "Kanbun"); + + /** + * Bopomofo Extended. + * 0x31A0 - 0x31BF. + * @since 1.4 + */ + public static final UnicodeBlock BOPOMOFO_EXTENDED + = new UnicodeBlock(0x31A0, 0x31BF, + "BOPOMOFO_EXTENDED", + "Bopomofo Extended"); + + /** + * Katakana Phonetic Extensions. + * 0x31F0 - 0x31FF. + * @since 1.5 + */ + public static final UnicodeBlock KATAKANA_PHONETIC_EXTENSIONS + = new UnicodeBlock(0x31F0, 0x31FF, + "KATAKANA_PHONETIC_EXTENSIONS", + "Katakana Phonetic Extensions"); + + /** + * Enclosed CJK Letters and Months. + * 0x3200 - 0x32FF. + */ + public static final UnicodeBlock ENCLOSED_CJK_LETTERS_AND_MONTHS + = new UnicodeBlock(0x3200, 0x32FF, + "ENCLOSED_CJK_LETTERS_AND_MONTHS", + "Enclosed CJK Letters and Months"); + + /** + * CJK Compatibility. + * 0x3300 - 0x33FF. + */ + public static final UnicodeBlock CJK_COMPATIBILITY + = new UnicodeBlock(0x3300, 0x33FF, + "CJK_COMPATIBILITY", + "CJK Compatibility"); + + /** + * CJK Unified Ideographs Extension A. + * 0x3400 - 0x4DBF. + * @since 1.4 + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A + = new UnicodeBlock(0x3400, 0x4DBF, + "CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A", + "CJK Unified Ideographs Extension A"); + + /** + * Yijing Hexagram Symbols. + * 0x4DC0 - 0x4DFF. + * @since 1.5 + */ + public static final UnicodeBlock YIJING_HEXAGRAM_SYMBOLS + = new UnicodeBlock(0x4DC0, 0x4DFF, + "YIJING_HEXAGRAM_SYMBOLS", + "Yijing Hexagram Symbols"); + + /** + * CJK Unified Ideographs. + * 0x4E00 - 0x9FFF. + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS + = new UnicodeBlock(0x4E00, 0x9FFF, + "CJK_UNIFIED_IDEOGRAPHS", + "CJK Unified Ideographs"); + + /** + * Yi Syllables. + * 0xA000 - 0xA48F. + * @since 1.4 + */ + public static final UnicodeBlock YI_SYLLABLES + = new UnicodeBlock(0xA000, 0xA48F, + "YI_SYLLABLES", + "Yi Syllables"); + + /** + * Yi Radicals. + * 0xA490 - 0xA4CF. + * @since 1.4 + */ + public static final UnicodeBlock YI_RADICALS + = new UnicodeBlock(0xA490, 0xA4CF, + "YI_RADICALS", + "Yi Radicals"); + + /** + * Hangul Syllables. + * 0xAC00 - 0xD7AF. + */ + public static final UnicodeBlock HANGUL_SYLLABLES + = new UnicodeBlock(0xAC00, 0xD7AF, + "HANGUL_SYLLABLES", + "Hangul Syllables"); + + /** + * High Surrogates. + * 0xD800 - 0xDB7F. + * @since 1.5 + */ + public static final UnicodeBlock HIGH_SURROGATES + = new UnicodeBlock(0xD800, 0xDB7F, + "HIGH_SURROGATES", + "High Surrogates"); + + /** + * High Private Use Surrogates. + * 0xDB80 - 0xDBFF. + * @since 1.5 + */ + public static final UnicodeBlock HIGH_PRIVATE_USE_SURROGATES + = new UnicodeBlock(0xDB80, 0xDBFF, + "HIGH_PRIVATE_USE_SURROGATES", + "High Private Use Surrogates"); + + /** + * Low Surrogates. + * 0xDC00 - 0xDFFF. + * @since 1.5 + */ + public static final UnicodeBlock LOW_SURROGATES + = new UnicodeBlock(0xDC00, 0xDFFF, + "LOW_SURROGATES", + "Low Surrogates"); + + /** + * Private Use Area. + * 0xE000 - 0xF8FF. + */ + public static final UnicodeBlock PRIVATE_USE_AREA + = new UnicodeBlock(0xE000, 0xF8FF, + "PRIVATE_USE_AREA", + "Private Use Area"); + + /** + * CJK Compatibility Ideographs. + * 0xF900 - 0xFAFF. + */ + public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS + = new UnicodeBlock(0xF900, 0xFAFF, + "CJK_COMPATIBILITY_IDEOGRAPHS", + "CJK Compatibility Ideographs"); + + /** + * Alphabetic Presentation Forms. + * 0xFB00 - 0xFB4F. + */ + public static final UnicodeBlock ALPHABETIC_PRESENTATION_FORMS + = new UnicodeBlock(0xFB00, 0xFB4F, + "ALPHABETIC_PRESENTATION_FORMS", + "Alphabetic Presentation Forms"); + + /** + * Arabic Presentation Forms-A. + * 0xFB50 - 0xFDFF. + */ + public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_A + = new UnicodeBlock(0xFB50, 0xFDFF, + "ARABIC_PRESENTATION_FORMS_A", + "Arabic Presentation Forms-A"); + + /** + * Variation Selectors. + * 0xFE00 - 0xFE0F. + * @since 1.5 + */ + public static final UnicodeBlock VARIATION_SELECTORS + = new UnicodeBlock(0xFE00, 0xFE0F, + "VARIATION_SELECTORS", + "Variation Selectors"); + + /** + * Combining Half Marks. + * 0xFE20 - 0xFE2F. + */ + public static final UnicodeBlock COMBINING_HALF_MARKS + = new UnicodeBlock(0xFE20, 0xFE2F, + "COMBINING_HALF_MARKS", + "Combining Half Marks"); + + /** + * CJK Compatibility Forms. + * 0xFE30 - 0xFE4F. + */ + public static final UnicodeBlock CJK_COMPATIBILITY_FORMS + = new UnicodeBlock(0xFE30, 0xFE4F, + "CJK_COMPATIBILITY_FORMS", + "CJK Compatibility Forms"); + + /** + * Small Form Variants. + * 0xFE50 - 0xFE6F. + */ + public static final UnicodeBlock SMALL_FORM_VARIANTS + = new UnicodeBlock(0xFE50, 0xFE6F, + "SMALL_FORM_VARIANTS", + "Small Form Variants"); + + /** + * Arabic Presentation Forms-B. + * 0xFE70 - 0xFEFF. + */ + public static final UnicodeBlock ARABIC_PRESENTATION_FORMS_B + = new UnicodeBlock(0xFE70, 0xFEFF, + "ARABIC_PRESENTATION_FORMS_B", + "Arabic Presentation Forms-B"); + + /** + * Halfwidth and Fullwidth Forms. + * 0xFF00 - 0xFFEF. + */ + public static final UnicodeBlock HALFWIDTH_AND_FULLWIDTH_FORMS + = new UnicodeBlock(0xFF00, 0xFFEF, + "HALFWIDTH_AND_FULLWIDTH_FORMS", + "Halfwidth and Fullwidth Forms"); + + /** + * Specials. + * 0xFFF0 - 0xFFFF. + */ + public static final UnicodeBlock SPECIALS + = new UnicodeBlock(0xFFF0, 0xFFFF, + "SPECIALS", + "Specials"); + + /** + * Linear B Syllabary. + * 0x10000 - 0x1007F. + * @since 1.5 + */ + public static final UnicodeBlock LINEAR_B_SYLLABARY + = new UnicodeBlock(0x10000, 0x1007F, + "LINEAR_B_SYLLABARY", + "Linear B Syllabary"); + + /** + * Linear B Ideograms. + * 0x10080 - 0x100FF. + * @since 1.5 + */ + public static final UnicodeBlock LINEAR_B_IDEOGRAMS + = new UnicodeBlock(0x10080, 0x100FF, + "LINEAR_B_IDEOGRAMS", + "Linear B Ideograms"); + + /** + * Aegean Numbers. + * 0x10100 - 0x1013F. + * @since 1.5 + */ + public static final UnicodeBlock AEGEAN_NUMBERS + = new UnicodeBlock(0x10100, 0x1013F, + "AEGEAN_NUMBERS", + "Aegean Numbers"); + + /** + * Old Italic. + * 0x10300 - 0x1032F. + * @since 1.5 + */ + public static final UnicodeBlock OLD_ITALIC + = new UnicodeBlock(0x10300, 0x1032F, + "OLD_ITALIC", + "Old Italic"); + + /** + * Gothic. + * 0x10330 - 0x1034F. + * @since 1.5 + */ + public static final UnicodeBlock GOTHIC + = new UnicodeBlock(0x10330, 0x1034F, + "GOTHIC", + "Gothic"); + + /** + * Ugaritic. + * 0x10380 - 0x1039F. + * @since 1.5 + */ + public static final UnicodeBlock UGARITIC + = new UnicodeBlock(0x10380, 0x1039F, + "UGARITIC", + "Ugaritic"); + + /** + * Deseret. + * 0x10400 - 0x1044F. + * @since 1.5 + */ + public static final UnicodeBlock DESERET + = new UnicodeBlock(0x10400, 0x1044F, + "DESERET", + "Deseret"); + + /** + * Shavian. + * 0x10450 - 0x1047F. + * @since 1.5 + */ + public static final UnicodeBlock SHAVIAN + = new UnicodeBlock(0x10450, 0x1047F, + "SHAVIAN", + "Shavian"); + + /** + * Osmanya. + * 0x10480 - 0x104AF. + * @since 1.5 + */ + public static final UnicodeBlock OSMANYA + = new UnicodeBlock(0x10480, 0x104AF, + "OSMANYA", + "Osmanya"); + + /** + * Cypriot Syllabary. + * 0x10800 - 0x1083F. + * @since 1.5 + */ + public static final UnicodeBlock CYPRIOT_SYLLABARY + = new UnicodeBlock(0x10800, 0x1083F, + "CYPRIOT_SYLLABARY", + "Cypriot Syllabary"); + + /** + * Byzantine Musical Symbols. + * 0x1D000 - 0x1D0FF. + * @since 1.5 + */ + public static final UnicodeBlock BYZANTINE_MUSICAL_SYMBOLS + = new UnicodeBlock(0x1D000, 0x1D0FF, + "BYZANTINE_MUSICAL_SYMBOLS", + "Byzantine Musical Symbols"); + + /** + * Musical Symbols. + * 0x1D100 - 0x1D1FF. + * @since 1.5 + */ + public static final UnicodeBlock MUSICAL_SYMBOLS + = new UnicodeBlock(0x1D100, 0x1D1FF, + "MUSICAL_SYMBOLS", + "Musical Symbols"); + + /** + * Tai Xuan Jing Symbols. + * 0x1D300 - 0x1D35F. + * @since 1.5 + */ + public static final UnicodeBlock TAI_XUAN_JING_SYMBOLS + = new UnicodeBlock(0x1D300, 0x1D35F, + "TAI_XUAN_JING_SYMBOLS", + "Tai Xuan Jing Symbols"); + + /** + * Mathematical Alphanumeric Symbols. + * 0x1D400 - 0x1D7FF. + * @since 1.5 + */ + public static final UnicodeBlock MATHEMATICAL_ALPHANUMERIC_SYMBOLS + = new UnicodeBlock(0x1D400, 0x1D7FF, + "MATHEMATICAL_ALPHANUMERIC_SYMBOLS", + "Mathematical Alphanumeric Symbols"); + + /** + * CJK Unified Ideographs Extension B. + * 0x20000 - 0x2A6DF. + * @since 1.5 + */ + public static final UnicodeBlock CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B + = new UnicodeBlock(0x20000, 0x2A6DF, + "CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B", + "CJK Unified Ideographs Extension B"); + + /** + * CJK Compatibility Ideographs Supplement. + * 0x2F800 - 0x2FA1F. + * @since 1.5 + */ + public static final UnicodeBlock CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT + = new UnicodeBlock(0x2F800, 0x2FA1F, + "CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT", + "CJK Compatibility Ideographs Supplement"); + + /** + * Tags. + * 0xE0000 - 0xE007F. + * @since 1.5 + */ + public static final UnicodeBlock TAGS + = new UnicodeBlock(0xE0000, 0xE007F, + "TAGS", + "Tags"); + + /** + * Variation Selectors Supplement. + * 0xE0100 - 0xE01EF. + * @since 1.5 + */ + public static final UnicodeBlock VARIATION_SELECTORS_SUPPLEMENT + = new UnicodeBlock(0xE0100, 0xE01EF, + "VARIATION_SELECTORS_SUPPLEMENT", + "Variation Selectors Supplement"); + + /** + * Supplementary Private Use Area-A. + * 0xF0000 - 0xFFFFF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_A + = new UnicodeBlock(0xF0000, 0xFFFFF, + "SUPPLEMENTARY_PRIVATE_USE_AREA_A", + "Supplementary Private Use Area-A"); + + /** + * Supplementary Private Use Area-B. + * 0x100000 - 0x10FFFF. + * @since 1.5 + */ + public static final UnicodeBlock SUPPLEMENTARY_PRIVATE_USE_AREA_B + = new UnicodeBlock(0x100000, 0x10FFFF, + "SUPPLEMENTARY_PRIVATE_USE_AREA_B", + "Supplementary Private Use Area-B"); + + /** + * Surrogates Area. + * 'D800' - 'DFFF'. + * @deprecated As of 1.5, the three areas, + * <a href="#HIGH_SURROGATES">HIGH_SURROGATES</a>, + * <a href="#HIGH_PRIVATE_USE_SURROGATES">HIGH_PRIVATE_USE_SURROGATES</a> + * and <a href="#LOW_SURROGATES">LOW_SURROGATES</a>, as defined + * by the Unicode standard, should be used in preference to + * this. These are also returned from calls to <code>of(int)</code> + * and <code>of(char)</code>. + */ + public static final UnicodeBlock SURROGATES_AREA + = new UnicodeBlock(0xD800, 0xDFFF, + "SURROGATES_AREA", + "Surrogates Area"); + + /** + * The defined subsets. + */ + private static final UnicodeBlock sets[] = { + BASIC_LATIN, + LATIN_1_SUPPLEMENT, + LATIN_EXTENDED_A, + LATIN_EXTENDED_B, + IPA_EXTENSIONS, + SPACING_MODIFIER_LETTERS, + COMBINING_DIACRITICAL_MARKS, + GREEK, + CYRILLIC, + CYRILLIC_SUPPLEMENTARY, + ARMENIAN, + HEBREW, + ARABIC, + SYRIAC, + THAANA, + DEVANAGARI, + BENGALI, + GURMUKHI, + GUJARATI, + ORIYA, + TAMIL, + TELUGU, + KANNADA, + MALAYALAM, + SINHALA, + THAI, + LAO, + TIBETAN, + MYANMAR, + GEORGIAN, + HANGUL_JAMO, + ETHIOPIC, + CHEROKEE, + UNIFIED_CANADIAN_ABORIGINAL_SYLLABICS, + OGHAM, + RUNIC, + TAGALOG, + HANUNOO, + BUHID, + TAGBANWA, + KHMER, + MONGOLIAN, + LIMBU, + TAI_LE, + KHMER_SYMBOLS, + PHONETIC_EXTENSIONS, + LATIN_EXTENDED_ADDITIONAL, + GREEK_EXTENDED, + GENERAL_PUNCTUATION, + SUPERSCRIPTS_AND_SUBSCRIPTS, + CURRENCY_SYMBOLS, + COMBINING_MARKS_FOR_SYMBOLS, + LETTERLIKE_SYMBOLS, + NUMBER_FORMS, + ARROWS, + MATHEMATICAL_OPERATORS, + MISCELLANEOUS_TECHNICAL, + CONTROL_PICTURES, + OPTICAL_CHARACTER_RECOGNITION, + ENCLOSED_ALPHANUMERICS, + BOX_DRAWING, + BLOCK_ELEMENTS, + GEOMETRIC_SHAPES, + MISCELLANEOUS_SYMBOLS, + DINGBATS, + MISCELLANEOUS_MATHEMATICAL_SYMBOLS_A, + SUPPLEMENTAL_ARROWS_A, + BRAILLE_PATTERNS, + SUPPLEMENTAL_ARROWS_B, + MISCELLANEOUS_MATHEMATICAL_SYMBOLS_B, + SUPPLEMENTAL_MATHEMATICAL_OPERATORS, + MISCELLANEOUS_SYMBOLS_AND_ARROWS, + CJK_RADICALS_SUPPLEMENT, + KANGXI_RADICALS, + IDEOGRAPHIC_DESCRIPTION_CHARACTERS, + CJK_SYMBOLS_AND_PUNCTUATION, + HIRAGANA, + KATAKANA, + BOPOMOFO, + HANGUL_COMPATIBILITY_JAMO, + KANBUN, + BOPOMOFO_EXTENDED, + KATAKANA_PHONETIC_EXTENSIONS, + ENCLOSED_CJK_LETTERS_AND_MONTHS, + CJK_COMPATIBILITY, + CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A, + YIJING_HEXAGRAM_SYMBOLS, + CJK_UNIFIED_IDEOGRAPHS, + YI_SYLLABLES, + YI_RADICALS, + HANGUL_SYLLABLES, + HIGH_SURROGATES, + HIGH_PRIVATE_USE_SURROGATES, + LOW_SURROGATES, + PRIVATE_USE_AREA, + CJK_COMPATIBILITY_IDEOGRAPHS, + ALPHABETIC_PRESENTATION_FORMS, + ARABIC_PRESENTATION_FORMS_A, + VARIATION_SELECTORS, + COMBINING_HALF_MARKS, + CJK_COMPATIBILITY_FORMS, + SMALL_FORM_VARIANTS, + ARABIC_PRESENTATION_FORMS_B, + HALFWIDTH_AND_FULLWIDTH_FORMS, + SPECIALS, + LINEAR_B_SYLLABARY, + LINEAR_B_IDEOGRAMS, + AEGEAN_NUMBERS, + OLD_ITALIC, + GOTHIC, + UGARITIC, + DESERET, + SHAVIAN, + OSMANYA, + CYPRIOT_SYLLABARY, + BYZANTINE_MUSICAL_SYMBOLS, + MUSICAL_SYMBOLS, + TAI_XUAN_JING_SYMBOLS, + MATHEMATICAL_ALPHANUMERIC_SYMBOLS, + CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, + CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT, + TAGS, + VARIATION_SELECTORS_SUPPLEMENT, + SUPPLEMENTARY_PRIVATE_USE_AREA_A, + SUPPLEMENTARY_PRIVATE_USE_AREA_B, + }; + } // class UnicodeBlock + + /** + * The immutable value of this Character. + * + * @serial the value of this Character + */ + private final char value; + + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3786198910865385080L; + + /** + * Smallest value allowed for radix arguments in Java. This value is 2. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MIN_RADIX = 2; + + /** + * Largest value allowed for radix arguments in Java. This value is 36. + * + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see Integer#toString(int, int) + * @see Integer#valueOf(String) + */ + public static final int MAX_RADIX = 36; + + /** + * The minimum value the char data type can hold. + * This value is <code>'\\u0000'</code>. + */ + public static final char MIN_VALUE = '\u0000'; + + /** + * The maximum value the char data type can hold. + * This value is <code>'\\uFFFF'</code>. + */ + public static final char MAX_VALUE = '\uFFFF'; + + /** + * Class object representing the primitive char data type. + * + * @since 1.1 + */ + public static final Class TYPE = VMClassLoader.getPrimitiveClass('C'); + + /** + * The number of bits needed to represent a <code>char</code>. + * @since 1.5 + */ + public static final int SIZE = 16; + + // This caches some Character values, and is used by boxing + // conversions via valueOf(). We must cache at least 0..127; + // this constant controls how much we actually cache. + private static final int MAX_CACHE = 127; + private static Character[] charCache = new Character[MAX_CACHE + 1]; + + /** + * Lu = Letter, Uppercase (Informative). + * + * @since 1.1 + */ + public static final byte UPPERCASE_LETTER = 1; + + /** + * Ll = Letter, Lowercase (Informative). + * + * @since 1.1 + */ + public static final byte LOWERCASE_LETTER = 2; + + /** + * Lt = Letter, Titlecase (Informative). + * + * @since 1.1 + */ + public static final byte TITLECASE_LETTER = 3; + + /** + * Mn = Mark, Non-Spacing (Normative). + * + * @since 1.1 + */ + public static final byte NON_SPACING_MARK = 6; + + /** + * Mc = Mark, Spacing Combining (Normative). + * + * @since 1.1 + */ + public static final byte COMBINING_SPACING_MARK = 8; + + /** + * Me = Mark, Enclosing (Normative). + * + * @since 1.1 + */ + public static final byte ENCLOSING_MARK = 7; + + /** + * Nd = Number, Decimal Digit (Normative). + * + * @since 1.1 + */ + public static final byte DECIMAL_DIGIT_NUMBER = 9; + + /** + * Nl = Number, Letter (Normative). + * + * @since 1.1 + */ + public static final byte LETTER_NUMBER = 10; + + /** + * No = Number, Other (Normative). + * + * @since 1.1 + */ + public static final byte OTHER_NUMBER = 11; + + /** + * Zs = Separator, Space (Normative). + * + * @since 1.1 + */ + public static final byte SPACE_SEPARATOR = 12; + + /** + * Zl = Separator, Line (Normative). + * + * @since 1.1 + */ + public static final byte LINE_SEPARATOR = 13; + + /** + * Zp = Separator, Paragraph (Normative). + * + * @since 1.1 + */ + public static final byte PARAGRAPH_SEPARATOR = 14; + + /** + * Cc = Other, Control (Normative). + * + * @since 1.1 + */ + public static final byte CONTROL = 15; + + /** + * Cf = Other, Format (Normative). + * + * @since 1.1 + */ + public static final byte FORMAT = 16; + + /** + * Cs = Other, Surrogate (Normative). + * + * @since 1.1 + */ + public static final byte SURROGATE = 19; + + /** + * Co = Other, Private Use (Normative). + * + * @since 1.1 + */ + public static final byte PRIVATE_USE = 18; + + /** + * Cn = Other, Not Assigned (Normative). + * + * @since 1.1 + */ + public static final byte UNASSIGNED = 0; + + /** + * Lm = Letter, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_LETTER = 4; + + /** + * Lo = Letter, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_LETTER = 5; + + /** + * Pc = Punctuation, Connector (Informative). + * + * @since 1.1 + */ + public static final byte CONNECTOR_PUNCTUATION = 23; + + /** + * Pd = Punctuation, Dash (Informative). + * + * @since 1.1 + */ + public static final byte DASH_PUNCTUATION = 20; + + /** + * Ps = Punctuation, Open (Informative). + * + * @since 1.1 + */ + public static final byte START_PUNCTUATION = 21; + + /** + * Pe = Punctuation, Close (Informative). + * + * @since 1.1 + */ + public static final byte END_PUNCTUATION = 22; + + /** + * Pi = Punctuation, Initial Quote (Informative). + * + * @since 1.4 + */ + public static final byte INITIAL_QUOTE_PUNCTUATION = 29; + + /** + * Pf = Punctuation, Final Quote (Informative). + * + * @since 1.4 + */ + public static final byte FINAL_QUOTE_PUNCTUATION = 30; + + /** + * Po = Punctuation, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_PUNCTUATION = 24; + + /** + * Sm = Symbol, Math (Informative). + * + * @since 1.1 + */ + public static final byte MATH_SYMBOL = 25; + + /** + * Sc = Symbol, Currency (Informative). + * + * @since 1.1 + */ + public static final byte CURRENCY_SYMBOL = 26; + + /** + * Sk = Symbol, Modifier (Informative). + * + * @since 1.1 + */ + public static final byte MODIFIER_SYMBOL = 27; + + /** + * So = Symbol, Other (Informative). + * + * @since 1.1 + */ + public static final byte OTHER_SYMBOL = 28; + + /** + * Undefined bidirectional character type. Undefined char values have + * undefined directionality in the Unicode specification. + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_UNDEFINED = -1; + + /** + * Strong bidirectional character type "L". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT = 0; + + /** + * Strong bidirectional character type "R". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT = 1; + + /** + * Strong bidirectional character type "AL". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC = 2; + + /** + * Weak bidirectional character type "EN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER = 3; + + /** + * Weak bidirectional character type "ES". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR = 4; + + /** + * Weak bidirectional character type "ET". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR = 5; + + /** + * Weak bidirectional character type "AN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_ARABIC_NUMBER = 6; + + /** + * Weak bidirectional character type "CS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_COMMON_NUMBER_SEPARATOR = 7; + + /** + * Weak bidirectional character type "NSM". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_NONSPACING_MARK = 8; + + /** + * Weak bidirectional character type "BN". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_BOUNDARY_NEUTRAL = 9; + + /** + * Neutral bidirectional character type "B". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_PARAGRAPH_SEPARATOR = 10; + + /** + * Neutral bidirectional character type "S". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_SEGMENT_SEPARATOR = 11; + + /** + * Strong bidirectional character type "WS". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_WHITESPACE = 12; + + /** + * Neutral bidirectional character type "ON". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_OTHER_NEUTRALS = 13; + + /** + * Strong bidirectional character type "LRE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING = 14; + + /** + * Strong bidirectional character type "LRO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE = 15; + + /** + * Strong bidirectional character type "RLE". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING = 16; + + /** + * Strong bidirectional character type "RLO". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE = 17; + + /** + * Weak bidirectional character type "PDF". + * + * @since 1.4 + */ + public static final byte DIRECTIONALITY_POP_DIRECTIONAL_FORMAT = 18; + + /** + * Mask for grabbing the type out of the result of readChar. + * @see #readChar(char) + */ + private static final int TYPE_MASK = 0x1F; + + /** + * Mask for grabbing the non-breaking space flag out of the result of + * readChar. + * @see #readChar(char) + */ + private static final int NO_BREAK_MASK = 0x20; + + /** + * Mask for grabbing the mirrored directionality flag out of the result + * of readChar. + * @see #readChar(char) + */ + private static final int MIRROR_MASK = 0x40; + + /** + * Min value for supplementary code point. + * + * @since 1.5 + */ + public static final int MIN_SUPPLEMENTARY_CODE_POINT = 0x10000; + + /** + * Min value for code point. + * + * @since 1.5 + */ + public static final int MIN_CODE_POINT = 0; + + + /** + * Max value for code point. + * + * @since 1.5 + */ + public static final int MAX_CODE_POINT = 0x010ffff; + + + /** + * Minimum high surrogate code in UTF-16 encoding. + * + * @since 1.5 + */ + public static final char MIN_HIGH_SURROGATE = '\ud800'; + + /** + * Maximum high surrogate code in UTF-16 encoding. + * + * @since 1.5 + */ + public static final char MAX_HIGH_SURROGATE = '\udbff'; + + /** + * Minimum low surrogate code in UTF-16 encoding. + * + * @since 1.5 + */ + public static final char MIN_LOW_SURROGATE = '\udc00'; + + /** + * Maximum low surrogate code in UTF-16 encoding. + * + * @since 1.5 + */ + public static final char MAX_LOW_SURROGATE = '\udfff'; + + /** + * Minimum surrogate code in UTF-16 encoding. + * + * @since 1.5 + */ + public static final char MIN_SURROGATE = MIN_HIGH_SURROGATE; + + /** + * Maximum low surrogate code in UTF-16 encoding. + * + * @since 1.5 + */ + public static final char MAX_SURROGATE = MAX_LOW_SURROGATE; + + /** + * Grabs an attribute offset from the Unicode attribute database. The lower + * 5 bits are the character type, the next 2 bits are flags, and the top + * 9 bits are the offset into the attribute tables. Note that the top 9 + * bits are meaningless in this context; they are useful only in the native + * code. + * + * @param ch the character to look up + * @return the character's attribute offset and type + * @see #TYPE_MASK + * @see #NO_BREAK_MASK + * @see #MIRROR_MASK + */ + private static native char readChar(char ch); + + /** + * Grabs an attribute offset from the Unicode attribute database. The lower + * 5 bits are the character type, the next 2 bits are flags, and the top + * 9 bits are the offset into the attribute tables. Note that the top 9 + * bits are meaningless in this context; they are useful only in the native + * code. + * + * @param codePoint the character to look up + * @return the character's attribute offset and type + * @see #TYPE_MASK + * @see #NO_BREAK_MASK + * @see #MIRROR_MASK + */ + private static native char readCodePoint(int codePoint); + + /** + * Wraps up a character. + * + * @param value the character to wrap + */ + public Character(char value) + { + this.value = value; + } + + /** + * Returns the character which has been wrapped by this class. + * + * @return the character wrapped + */ + public char charValue() + { + return value; + } + + /** + * Returns the numerical value (unsigned) of the wrapped character. + * Range of returned values: 0x0000-0xFFFF. + * + * @return the value of the wrapped character + */ + public int hashCode() + { + return value; + } + + /** + * Determines if an object is equal to this object. This is only true for + * another Character object wrapping the same value. + * + * @param o object to compare + * @return true if o is a Character with the same value + */ + public boolean equals(Object o) + { + return o instanceof Character && value == ((Character) o).value; + } + + /** + * Converts the wrapped character into a String. + * + * @return a String containing one character -- the wrapped character + * of this instance + */ + public String toString() + { + // This assumes that String.valueOf(char) can create a single-character + // String more efficiently than through the public API. + return String.valueOf(value); + } + + /** + * Returns a String of length 1 representing the specified character. + * + * @param ch the character to convert + * @return a String containing the character + * @since 1.4 + */ + public static String toString(char ch) + { + // This assumes that String.valueOf(char) can create a single-character + // String more efficiently than through the public API. + return String.valueOf(ch); + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * <code>'a'</code> is lowercase. + * <br> + * lowercase = [Ll] + * + * @param ch character to test + * @return true if ch is a Unicode lowercase letter, else false + * @see #isUpperCase(char) + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #getType(char) + */ + public static boolean isLowerCase(char ch) + { + return getType(ch) == LOWERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode lowercase letter. For example, + * <code>'a'</code> is lowercase. Unlike isLowerCase(char), this method + * supports supplementary Unicode code points. + * <br> + * lowercase = [Ll] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode lowercase letter, else false + * @see #isUpperCase(int) + * @see #isTitleCase(int) + * @see #toLowerCase(int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isLowerCase(int codePoint) + { + return getType(codePoint) == LOWERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * <code>'A'</code> is uppercase. + * <br> + * uppercase = [Lu] + * + * @param ch character to test + * @return true if ch is a Unicode uppercase letter, else false + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #toUpperCase(char) + * @see #getType(char) + */ + public static boolean isUpperCase(char ch) + { + return getType(ch) == UPPERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode uppercase letter. For example, + * <code>'A'</code> is uppercase. Unlike isUpperCase(char), this method + * supports supplementary Unicode code points. + * <br> + * uppercase = [Lu] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode uppercase letter, else false + * @see #isLowerCase(int) + * @see #isTitleCase(int) + * @see #toUpperCase(int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isUpperCase(int codePoint) + { + return getType(codePoint) == UPPERCASE_LETTER; + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * <br> + * titlecase = [Lt] + * + * @param ch character to test + * @return true if ch is a Unicode titlecase letter, else false + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #getType(char) + */ + public static boolean isTitleCase(char ch) + { + return getType(ch) == TITLECASE_LETTER; + } + + /** + * Determines if a character is a Unicode titlecase letter. For example, + * the character "Lj" (Latin capital L with small letter j) is titlecase. + * Unlike isTitleCase(char), this method supports supplementary Unicode + * code points. + * <br> + * titlecase = [Lt] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode titlecase letter, else false + * @see #isLowerCase(int) + * @see #isUpperCase(int) + * @see #toTitleCase(int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isTitleCase(int codePoint) + { + return getType(codePoint) == TITLECASE_LETTER; + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * <code>'0'</code> is a digit. + * <br> + * Unicode decimal digit = [Nd] + * + * @param ch character to test + * @return true if ch is a Unicode decimal digit, else false + * @see #digit(char, int) + * @see #forDigit(int, int) + * @see #getType(char) + */ + public static boolean isDigit(char ch) + { + return getType(ch) == DECIMAL_DIGIT_NUMBER; + } + + /** + * Determines if a character is a Unicode decimal digit. For example, + * <code>'0'</code> is a digit. Unlike isDigit(char), this method + * supports supplementary Unicode code points. + * <br> + * Unicode decimal digit = [Nd] + * + * @param codePoint character to test + * @return true if ccodePoint is a Unicode decimal digit, else false + * @see #digit(int, int) + * @see #forDigit(int, int) + * @see #getType(int) + * @since 1.5 + */ + public static boolean isDigit(int codePoint) + { + return getType(codePoint) == DECIMAL_DIGIT_NUMBER; + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. + * <br> + * defined = not [Cn] + * + * @param ch character to test + * @return true if ch is a Unicode character, else false + * @see #isDigit(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUpperCase(char) + */ + public static boolean isDefined(char ch) + { + return getType(ch) != UNASSIGNED; + } + + /** + * Determines if a character is part of the Unicode Standard. This is an + * evolving standard, but covers every character in the data file. Unlike + * isDefined(char), this method supports supplementary Unicode code points. + * <br> + * defined = not [Cn] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode character, else false + * @see #isDigit(int) + * @see #isLetter(int) + * @see #isLetterOrDigit(int) + * @see #isLowerCase(int) + * @see #isTitleCase(int) + * @see #isUpperCase(int) + * @since 1.5 + */ + public static boolean isDefined(int codePoint) + { + return getType(codePoint) != UNASSIGNED; + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * <br> + * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param ch character to test + * @return true if ch is a Unicode letter, else false + * @see #isDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetterOrDigit(char) + * @see #isLowerCase(char) + * @see #isTitleCase(char) + * @see #isUnicodeIdentifierStart(char) + * @see #isUpperCase(char) + */ + public static boolean isLetter(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; + } + + /** + * Determines if a character is a Unicode letter. Not all letters have case, + * so this may return true when isLowerCase and isUpperCase return false. + * Unlike isLetter(char), this method supports supplementary Unicode code + * points. + * <br> + * letter = [Lu]|[Ll]|[Lt]|[Lm]|[Lo] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode letter, else false + * @see #isDigit(int) + * @see #isJavaIdentifierStart(int) + * @see #isJavaLetter(int) + * @see #isJavaLetterOrDigit(int) + * @see #isLetterOrDigit(int) + * @see #isLowerCase(int) + * @see #isTitleCase(int) + * @see #isUnicodeIdentifierStart(int) + * @see #isUpperCase(int) + * @since 1.5 + */ + public static boolean isLetter(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER))) != 0; + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. + * <br> + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param ch character to test + * @return true if ch is a Unicode letter or a Unicode digit, else false + * @see #isDigit(char) + * @see #isJavaIdentifierPart(char) + * @see #isJavaLetter(char) + * @see #isJavaLetterOrDigit(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + */ + public static boolean isLetterOrDigit(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0; + } + + /** + * Determines if a character is a Unicode letter or a Unicode digit. This + * is the combination of isLetter and isDigit. Unlike isLetterOrDigit(char), + * this method supports supplementary Unicode code points. + * <br> + * letter or digit = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nd] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode letter or a Unicode digit, else false + * @see #isDigit(int) + * @see #isJavaIdentifierPart(int) + * @see #isJavaLetter(int) + * @see #isJavaLetterOrDigit(int) + * @see #isLetter(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isLetterOrDigit(int codePoint) + { + return ((1 << getType(codePoint) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER))) != 0); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @deprecated Replaced by {@link #isJavaIdentifierStart(char)} + * @see #isJavaLetterOrDigit(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + */ + public static boolean isJavaLetter(char ch) + { + return isJavaIdentifierStart(ch); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). Unlike isJavaIdentifierStart(char), this method supports + * supplementary Unicode code points. + * <br> + * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param codePoint character to test + * @return true if codePoint can start a Java identifier, else false + * @see #isJavaIdentifierPart(int) + * @see #isLetter(int) + * @see #isUnicodeIdentifierStart(int) + * @since 1.5 + */ + public static boolean isJavaIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @deprecated Replaced by {@link #isJavaIdentifierPart(char)} + * @see #isJavaLetter(char) + * @see #isJavaIdentifierStart(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @see #isIdentifierIgnorable(char) + */ + public static boolean isJavaLetterOrDigit(char ch) + { + return isJavaIdentifierPart(ch); + } + + /** + * Determines if a character can start a Java identifier. This is the + * combination of isLetter, any character where getType returns + * LETTER_NUMBER, currency symbols (like '$'), and connecting punctuation + * (like '_'). + * <br> + * Java identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc] + * + * @param ch character to test + * @return true if ch can start a Java identifier, else false + * @see #isJavaIdentifierPart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierStart(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. + * <br> + * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierStart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isJavaIdentifierPart(char ch) + { + int category = getType(ch); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(ch)); + } + + /** + * Determines if a character can follow the first letter in + * a Java identifier. This is the combination of isJavaLetter (isLetter, + * type of LETTER_NUMBER, currency, connecting punctuation) and digit, + * numeric letter (like Roman numerals), combining marks, non-spacing marks, + * or isIdentifierIgnorable. Unlike isJavaIdentifierPart(char), this method + * supports supplementary Unicode code points. + * <br> + * Java identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Sc]|[Pc]|[Mn]|[Mc]|[Nd]|[Cf] + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if codePoint can follow the first letter in a Java identifier + * @see #isIdentifierIgnorable(int) + * @see #isJavaIdentifierStart(int) + * @see #isLetterOrDigit(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isJavaIdentifierPart(int codePoint) + { + int category = getType(codePoint); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CURRENCY_SYMBOL) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(codePoint)); + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. + * <br> + * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param ch character to test + * @return true if ch can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(char) + * @see #isLetter(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierStart(char ch) + { + return ((1 << getType(ch)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER))) != 0; + } + + /** + * Determines if a character can start a Unicode identifier. Only + * letters can start a Unicode identifier, but this includes characters + * in LETTER_NUMBER. Unlike isUnicodeIdentifierStart(char), this method + * supports supplementary Unicode code points. + * <br> + * Unicode identifier start = [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl] + * + * @param codePoint character to test + * @return true if codePoint can start a Unicode identifier, else false + * @see #isJavaIdentifierStart(int) + * @see #isLetter(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierStart(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << LETTER_NUMBER))) != 0; + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. + * <br> + * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param ch character to test + * @return true if ch can follow the first letter in a Unicode identifier + * @see #isIdentifierIgnorable(char) + * @see #isJavaIdentifierPart(char) + * @see #isLetterOrDigit(char) + * @see #isUnicodeIdentifierStart(char) + * @since 1.1 + */ + public static boolean isUnicodeIdentifierPart(char ch) + { + int category = getType(ch); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(ch)); + } + + /** + * Determines if a character can follow the first letter in + * a Unicode identifier. This includes letters, connecting punctuation, + * digits, numeric letters, combining marks, non-spacing marks, and + * isIdentifierIgnorable. Unlike isUnicodeIdentifierPart(char), this method + * supports supplementary Unicode code points. + * <br> + * Unicode identifier extender = + * [Lu]|[Ll]|[Lt]|[Lm]|[Lo]|[Nl]|[Mn]|[Mc]|[Nd]|[Pc]|[Cf]| + * |U+0000-U+0008|U+000E-U+001B|U+007F-U+009F + * + * @param codePoint character to test + * @return true if codePoint can follow the first letter in a Unicode + * identifier + * @see #isIdentifierIgnorable(int) + * @see #isJavaIdentifierPart(int) + * @see #isLetterOrDigit(int) + * @see #isUnicodeIdentifierStart(int) + * @since 1.5 + */ + public static boolean isUnicodeIdentifierPart(int codePoint) + { + int category = getType(codePoint); + return ((1 << category) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << TITLECASE_LETTER) + | (1 << MODIFIER_LETTER) + | (1 << OTHER_LETTER) + | (1 << NON_SPACING_MARK) + | (1 << COMBINING_SPACING_MARK) + | (1 << DECIMAL_DIGIT_NUMBER) + | (1 << LETTER_NUMBER) + | (1 << CONNECTOR_PUNCTUATION) + | (1 << FORMAT))) != 0 + || (category == CONTROL && isIdentifierIgnorable(codePoint)); + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters (<code>'\u0000'</code> + * through <code>'\u0008'</code>, <code>'\u000E'</code> through + * <code>'\u001B'</code>, and <code>'\u007F'</code> through + * <code>'\u009F'</code>), and FORMAT characters. + * <br> + * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param ch character to test + * @return true if ch is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(char) + * @see #isUnicodeIdentifierPart(char) + * @since 1.1 + */ + public static boolean isIdentifierIgnorable(char ch) + { + return (ch <= '\u009F' && (ch < '\t' || ch >= '\u007F' + || (ch <= '\u001B' && ch >= '\u000E'))) + || getType(ch) == FORMAT; + } + + /** + * Determines if a character is ignorable in a Unicode identifier. This + * includes the non-whitespace ISO control characters (<code>'\u0000'</code> + * through <code>'\u0008'</code>, <code>'\u000E'</code> through + * <code>'\u001B'</code>, and <code>'\u007F'</code> through + * <code>'\u009F'</code>), and FORMAT characters. Unlike + * isIdentifierIgnorable(char), this method supports supplementary Unicode + * code points. + * <br> + * Unicode identifier ignorable = [Cf]|U+0000-U+0008|U+000E-U+001B + * |U+007F-U+009F + * + * @param codePoint character to test + * @return true if codePoint is ignorable in a Unicode or Java identifier + * @see #isJavaIdentifierPart(int) + * @see #isUnicodeIdentifierPart(int) + * @since 1.5 + */ + public static boolean isIdentifierIgnorable(int codePoint) + { + return ((codePoint >= 0 && codePoint <= 0x0008) + || (codePoint >= 0x000E && codePoint <= 0x001B) + || (codePoint >= 0x007F && codePoint <= 0x009F) + || getType(codePoint) == FORMAT); + } + + /** + * Converts a Unicode character into its lowercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isLowerCase(toLowerCase(ch)) does not always return true. + * + * @param ch character to convert to lowercase + * @return lowercase mapping of ch, or ch if lowercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toTitleCase(char) + * @see #toUpperCase(char) + */ + public static native char toLowerCase(char ch); + + /** + * Converts a Unicode character into its lowercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isLowerCase(toLowerCase(codePoint)) does not always return true. + * Unlike toLowerCase(char), this method supports supplementary Unicode + * code points. + * + * @param codePoint character to convert to lowercase + * @return lowercase mapping of codePoint, or codePoint if lowercase + * mapping does not exist + * @see #isLowerCase(int) + * @see #isUpperCase(int) + * @see #toTitleCase(int) + * @see #toUpperCase(int) + * @since 1.5 + */ + public static native int toLowerCase(int codePoint); + + /** + * Converts a Unicode character into its uppercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isUpperCase(toUpperCase(ch)) does not always return true. + * + * @param ch character to convert to uppercase + * @return uppercase mapping of ch, or ch if uppercase mapping does + * not exist + * @see #isLowerCase(char) + * @see #isUpperCase(char) + * @see #toLowerCase(char) + * @see #toTitleCase(char) + */ + public static native char toUpperCase(char ch); + + /** + * Converts a Unicode character into its uppercase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isUpperCase(toUpperCase(codePoint)) does not always return true. + * Unlike toUpperCase(char), this method supports supplementary + * Unicode code points. + * + * @param codePoint character to convert to uppercase + * @return uppercase mapping of codePoint, or codePoint if uppercase + * mapping does not exist + * @see #isLowerCase(int) + * @see #isUpperCase(int) + * @see #toLowerCase(int) + * @see #toTitleCase(int) + * @since 1.5 + */ + public static native int toUpperCase(int codePoint); + + /** + * Converts a Unicode character into its titlecase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isTitleCase(toTitleCase(ch)) does not always return true. + * + * @param ch character to convert to titlecase + * @return titlecase mapping of ch, or ch if titlecase mapping does + * not exist + * @see #isTitleCase(char) + * @see #toLowerCase(char) + * @see #toUpperCase(char) + */ + public static native char toTitleCase(char ch); + + /** + * Converts a Unicode character into its titlecase equivalent mapping. + * If a mapping does not exist, then the character passed is returned. + * Note that isTitleCase(toTitleCase(codePoint)) does not always return true. + * Unlike toTitleCase(char), this method supports supplementary + * Unicode code points. + * + * @param codePoint character to convert to titlecase + * @return titlecase mapping of codePoint, or codePoint if titlecase + * mapping does not exist + * @see #isTitleCase(int) + * @see #toLowerCase(int) + * @see #toUpperCase(int) + * @since 1.5 + */ + public static native int toTitleCase(int codePoint); + + /** + * Converts a character into a digit of the specified radix. If the radix + * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(ch) + * exceeds the radix, or if ch is not a decimal digit or in the case + * insensitive set of 'a'-'z', the result is -1. + * <br> + * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param ch character to convert into a digit + * @param radix radix in which ch is a digit + * @return digit which ch represents in radix, or -1 not a valid digit + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #forDigit(int, int) + * @see #isDigit(char) + * @see #getNumericValue(char) + */ + public static native int digit(char ch, int radix); + + /** + * Converts a character into a digit of the specified radix. If the radix + * exceeds MIN_RADIX or MAX_RADIX, or if the result of getNumericValue(int) + * exceeds the radix, or if codePoint is not a decimal digit or in the case + * insensitive set of 'a'-'z', the result is -1. Unlike digit(char, int), + * this method supports supplementary Unicode code points. + * <br> + * character argument boundary = [Nd]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param codePoint character to convert into a digit + * @param radix radix in which codePoint is a digit + * @return digit which codePoint represents in radix, or -1 not a valid digit + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #forDigit(int, int) + * @see #isDigit(int) + * @see #getNumericValue(int) + * @since 1.5 + */ + public static native int digit(int codePoint, int radix); + + /** + * Returns the Unicode numeric value property of a character. For example, + * <code>'\\u216C'</code> (the Roman numeral fifty) returns 50. + * + * <p>This method also returns values for the letters A through Z, (not + * specified by Unicode), in these ranges: <code>'\u0041'</code> + * through <code>'\u005A'</code> (uppercase); <code>'\u0061'</code> + * through <code>'\u007A'</code> (lowercase); and <code>'\uFF21'</code> + * through <code>'\uFF3A'</code>, <code>'\uFF41'</code> through + * <code>'\uFF5A'</code> (full width variants). + * + * <p>If the character lacks a numeric value property, -1 is returned. + * If the character has a numeric value property which is not representable + * as a nonnegative integer, such as a fraction, -2 is returned. + * + * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param ch character from which the numeric value property will + * be retrieved + * @return the numeric value property of ch, or -1 if it does not exist, or + * -2 if it is not representable as a nonnegative integer + * @see #forDigit(int, int) + * @see #digit(char, int) + * @see #isDigit(char) + * @since 1.1 + */ + public static native int getNumericValue(char ch); + + /** + * Returns the Unicode numeric value property of a character. For example, + * <code>'\\u216C'</code> (the Roman numeral fifty) returns 50. + * + * <p>This method also returns values for the letters A through Z, (not + * specified by Unicode), in these ranges: <code>'\u0041'</code> + * through <code>'\u005A'</code> (uppercase); <code>'\u0061'</code> + * through <code>'\u007A'</code> (lowercase); and <code>'\uFF21'</code> + * through <code>'\uFF3A'</code>, <code>'\uFF41'</code> through + * <code>'\uFF5A'</code> (full width variants). + * + * <p>If the character lacks a numeric value property, -1 is returned. + * If the character has a numeric value property which is not representable + * as a nonnegative integer, such as a fraction, -2 is returned. + * + * Unlike getNumericValue(char), this method supports supplementary Unicode + * code points. + * + * character argument boundary = [Nd]|[Nl]|[No]|U+0041-U+005A|U+0061-U+007A + * |U+FF21-U+FF3A|U+FF41-U+FF5A + * + * @param codePoint character from which the numeric value property will + * be retrieved + * @return the numeric value property of codePoint, or -1 if it does not + * exist, or -2 if it is not representable as a nonnegative integer + * @see #forDigit(int, int) + * @see #digit(int, int) + * @see #isDigit(int) + * @since 1.5 + */ + public static native int getNumericValue(int codePoint); + + /** + * Determines if a character is a ISO-LATIN-1 space. This is only the five + * characters <code>'\t'</code>, <code>'\n'</code>, <code>'\f'</code>, + * <code>'\r'</code>, and <code>' '</code>. + * <br> + * Java space = U+0020|U+0009|U+000A|U+000C|U+000D + * + * @param ch character to test + * @return true if ch is a space, else false + * @deprecated Replaced by {@link #isWhitespace(char)} + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + */ + public static boolean isSpace(char ch) + { + // Performing the subtraction up front alleviates need to compare longs. + return ch-- <= ' ' && ((1 << ch) + & ((1 << (' ' - 1)) + | (1 << ('\t' - 1)) + | (1 << ('\n' - 1)) + | (1 << ('\r' - 1)) + | (1 << ('\f' - 1)))) != 0; + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. + * <br> + * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param ch character to test + * @return true if ch is a Unicode space, else false + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isSpaceChar(char ch) + { + return ((1 << getType(ch)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0; + } + + /** + * Determines if a character is a Unicode space character. This includes + * SPACE_SEPARATOR, LINE_SEPARATOR, and PARAGRAPH_SEPARATOR. Unlike + * isSpaceChar(char), this method supports supplementary Unicode code points. + * <br> + * Unicode space = [Zs]|[Zp]|[Zl] + * + * @param codePoint character to test + * @return true if codePoint is a Unicode space, else false + * @see #isWhitespace(int) + * @since 1.5 + */ + public static boolean isSpaceChar(int codePoint) + { + return ((1 << getType(codePoint)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0; + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * (<code>'\u00A0'</code>, <code>'\u2007'</code>, and <code>'\u202F'</code>); + * and these characters: <code>'\u0009'</code>, <code>'\u000A'</code>, + * <code>'\u000B'</code>, <code>'\u000C'</code>, <code>'\u000D'</code>, + * <code>'\u001C'</code>, <code>'\u001D'</code>, <code>'\u001E'</code>, + * and <code>'\u001F'</code>. + * <br> + * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param ch character to test + * @return true if ch is Java whitespace, else false + * @see #isSpaceChar(char) + * @since 1.1 + */ + public static boolean isWhitespace(char ch) + { + int attr = readChar(ch); + return ((((1 << (attr & TYPE_MASK)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0) + && (attr & NO_BREAK_MASK) == 0) + || (ch <= '\u001F' && ((1 << ch) + & ((1 << '\t') + | (1 << '\n') + | (1 << '\u000B') + | (1 << '\u000C') + | (1 << '\r') + | (1 << '\u001C') + | (1 << '\u001D') + | (1 << '\u001E') + | (1 << '\u001F'))) != 0); + } + + /** + * Determines if a character is Java whitespace. This includes Unicode + * space characters (SPACE_SEPARATOR, LINE_SEPARATOR, and + * PARAGRAPH_SEPARATOR) except the non-breaking spaces + * (<code>'\u00A0'</code>, <code>'\u2007'</code>, and <code>'\u202F'</code>); + * and these characters: <code>'\u0009'</code>, <code>'\u000A'</code>, + * <code>'\u000B'</code>, <code>'\u000C'</code>, <code>'\u000D'</code>, + * <code>'\u001C'</code>, <code>'\u001D'</code>, <code>'\u001E'</code>, + * and <code>'\u001F'</code>. Unlike isWhitespace(char), this method + * supports supplementary Unicode code points. + * <br> + * Java whitespace = ([Zs] not Nb)|[Zl]|[Zp]|U+0009-U+000D|U+001C-U+001F + * + * @param codePoint character to test + * @return true if codePoint is Java whitespace, else false + * @see #isSpaceChar(int) + * @since 1.5 + */ + public static boolean isWhitespace(int codePoint) + { + int plane = codePoint >>> 16; + if (plane > 2 && plane != 14) + return false; + int attr = readCodePoint(codePoint); + return ((((1 << (attr & TYPE_MASK)) + & ((1 << SPACE_SEPARATOR) + | (1 << LINE_SEPARATOR) + | (1 << PARAGRAPH_SEPARATOR))) != 0) + && (attr & NO_BREAK_MASK) == 0) + || (codePoint <= '\u001F' && ((1 << codePoint) + & ((1 << '\t') + | (1 << '\n') + | (1 << '\u000B') + | (1 << '\u000C') + | (1 << '\r') + | (1 << '\u001C') + | (1 << '\u001D') + | (1 << '\u001E') + | (1 << '\u001F'))) != 0); + } + + /** + * Determines if a character has the ISO Control property. + * <br> + * ISO Control = [Cc] + * + * @param ch character to test + * @return true if ch is an ISO Control character, else false + * @see #isSpaceChar(char) + * @see #isWhitespace(char) + * @since 1.1 + */ + public static boolean isISOControl(char ch) + { + return getType(ch) == CONTROL; + } + + /** + * Determines if a character has the ISO Control property. Unlike + * isISOControl(char), this method supports supplementary unicode + * code points. + * <br> + * ISO Control = [Cc] + * + * @param codePoint character to test + * @return true if codePoint is an ISO Control character, else false + * @see #isSpaceChar(int) + * @see #isWhitespace(int) + * @since 1.5 + */ + public static boolean isISOControl(int codePoint) + { + return getType(codePoint) == CONTROL; + } + + /** + * Returns the Unicode general category property of a character. + * + * @param ch character from which the general category property will + * be retrieved + * @return the character category property of ch as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * @since 1.1 + */ + public static native int getType(char ch); + + /** + * Returns the Unicode general category property of a character. Supports + * supplementary Unicode code points. + * + * @param codePoint character from which the general category property will + * be retrieved + * @return the character category property of codePoint as an integer + * @see #UNASSIGNED + * @see #UPPERCASE_LETTER + * @see #LOWERCASE_LETTER + * @see #TITLECASE_LETTER + * @see #MODIFIER_LETTER + * @see #OTHER_LETTER + * @see #NON_SPACING_MARK + * @see #ENCLOSING_MARK + * @see #COMBINING_SPACING_MARK + * @see #DECIMAL_DIGIT_NUMBER + * @see #LETTER_NUMBER + * @see #OTHER_NUMBER + * @see #SPACE_SEPARATOR + * @see #LINE_SEPARATOR + * @see #PARAGRAPH_SEPARATOR + * @see #CONTROL + * @see #FORMAT + * @see #PRIVATE_USE + * @see #SURROGATE + * @see #DASH_PUNCTUATION + * @see #START_PUNCTUATION + * @see #END_PUNCTUATION + * @see #CONNECTOR_PUNCTUATION + * @see #OTHER_PUNCTUATION + * @see #MATH_SYMBOL + * @see #CURRENCY_SYMBOL + * @see #MODIFIER_SYMBOL + * @see #INITIAL_QUOTE_PUNCTUATION + * @see #FINAL_QUOTE_PUNCTUATION + * @since 1.5 + */ + public static native int getType(int codePoint); + + /** + * Converts a digit into a character which represents that digit + * in a specified radix. If the radix exceeds MIN_RADIX or MAX_RADIX, + * or the digit exceeds the radix, then the null character <code>'\0'</code> + * is returned. Otherwise the return value is in '0'-'9' and 'a'-'z'. + * <br> + * return value boundary = U+0030-U+0039|U+0061-U+007A + * + * @param digit digit to be converted into a character + * @param radix radix of digit + * @return character representing digit in radix, or '\0' + * @see #MIN_RADIX + * @see #MAX_RADIX + * @see #digit(char, int) + */ + public static char forDigit(int digit, int radix) + { + if (radix < MIN_RADIX || radix > MAX_RADIX + || digit < 0 || digit >= radix) + return '\0'; + return (char) (digit < 10 ? ('0' + digit) : ('a' - 10 + digit)); + } + + /** + * Returns the Unicode directionality property of the character. This + * is used in the visual ordering of text. + * + * @param ch the character to look up + * @return the directionality constant, or DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_LEFT_TO_RIGHT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC + * @see #DIRECTIONALITY_EUROPEAN_NUMBER + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR + * @see #DIRECTIONALITY_ARABIC_NUMBER + * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_NONSPACING_MARK + * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL + * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR + * @see #DIRECTIONALITY_SEGMENT_SEPARATOR + * @see #DIRECTIONALITY_WHITESPACE + * @see #DIRECTIONALITY_OTHER_NEUTRALS + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE + * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @since 1.4 + */ + public static native byte getDirectionality(char ch); + + /** + * Returns the Unicode directionality property of the character. This + * is used in the visual ordering of text. Unlike getDirectionality(char), + * this method supports supplementary Unicode code points. + * + * @param codePoint the character to look up + * @return the directionality constant, or DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_UNDEFINED + * @see #DIRECTIONALITY_LEFT_TO_RIGHT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC + * @see #DIRECTIONALITY_EUROPEAN_NUMBER + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR + * @see #DIRECTIONALITY_ARABIC_NUMBER + * @see #DIRECTIONALITY_COMMON_NUMBER_SEPARATOR + * @see #DIRECTIONALITY_NONSPACING_MARK + * @see #DIRECTIONALITY_BOUNDARY_NEUTRAL + * @see #DIRECTIONALITY_PARAGRAPH_SEPARATOR + * @see #DIRECTIONALITY_SEGMENT_SEPARATOR + * @see #DIRECTIONALITY_WHITESPACE + * @see #DIRECTIONALITY_OTHER_NEUTRALS + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING + * @see #DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING + * @see #DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE + * @see #DIRECTIONALITY_POP_DIRECTIONAL_FORMAT + * @since 1.5 + */ + public static native byte getDirectionality(int codePoint); + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, <code>\u0028</code> (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. + * + * @param ch the character to look up + * @return true if the character is mirrored + * @since 1.4 + */ + public static boolean isMirrored(char ch) + { + return (readChar(ch) & MIRROR_MASK) != 0; + } + + /** + * Determines whether the character is mirrored according to Unicode. For + * example, <code>\u0028</code> (LEFT PARENTHESIS) appears as '(' in + * left-to-right text, but ')' in right-to-left text. Unlike + * isMirrored(char), this method supports supplementary Unicode code points. + * + * @param codePoint the character to look up + * @return true if the character is mirrored + * @since 1.5 + */ + public static boolean isMirrored(int codePoint) + { + int plane = codePoint >>> 16; + if (plane > 2 && plane != 14) + return false; + return (readCodePoint(codePoint) & MIRROR_MASK) != 0; + } + + /** + * Compares another Character to this Character, numerically. + * + * @param anotherCharacter Character to compare with this Character + * @return a negative integer if this Character is less than + * anotherCharacter, zero if this Character is equal, and + * a positive integer if this Character is greater + * @throws NullPointerException if anotherCharacter is null + * @since 1.2 + */ + public int compareTo(Character anotherCharacter) + { + return value - anotherCharacter.value; + } + + /** + * Compares an object to this Character. Assuming the object is a + * Character object, this method performs the same comparison as + * compareTo(Character). + * + * @param o object to compare + * @return the comparison value + * @throws ClassCastException if o is not a Character object + * @throws NullPointerException if o is null + * @see #compareTo(Character) + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((Character) o); + } + + /** + * Returns an <code>Character</code> object wrapping the value. + * In contrast to the <code>Character</code> constructor, this method + * will cache some values. It is used by boxing conversion. + * + * @param val the value to wrap + * @return the <code>Character</code> + * + * @since 1.5 + */ + public static Character valueOf(char val) + { + if (val > MAX_CACHE) + return new Character(val); + synchronized (charCache) + { + if (charCache[val - MIN_VALUE] == null) + charCache[val - MIN_VALUE] = new Character(val); + return charCache[val - MIN_VALUE]; + } + } + + /** + * Reverse the bytes in val. + * @since 1.5 + */ + public static char reverseBytes(char val) + { + return (char) (((val >> 8) & 0xff) | ((val << 8) & 0xff00)); + } + + /** + * Converts a unicode code point to a UTF-16 representation of that + * code point. + * + * @param codePoint the unicode code point + * + * @return the UTF-16 representation of that code point + * + * @throws IllegalArgumentException if the code point is not a valid + * unicode code point + * + * @since 1.5 + */ + public static char[] toChars(int codePoint) + { + char[] result = new char[charCount(codePoint)]; + int ignore = toChars(codePoint, result, 0); + return result; + } + + /** + * Converts a unicode code point to its UTF-16 representation. + * + * @param codePoint the unicode code point + * @param dst the target char array + * @param dstIndex the start index for the target + * + * @return number of characters written to <code>dst</code> + * + * @throws IllegalArgumentException if <code>codePoint</code> is not a + * valid unicode code point + * @throws NullPointerException if <code>dst</code> is <code>null</code> + * @throws IndexOutOfBoundsException if <code>dstIndex</code> is not valid + * in <code>dst</code> or if the UTF-16 representation does not + * fit into <code>dst</code> + * + * @since 1.5 + */ + public static int toChars(int codePoint, char[] dst, int dstIndex) + { + if (!isValidCodePoint(codePoint)) + { + throw new IllegalArgumentException("not a valid code point: " + + codePoint); + } + + int result; + if (isSupplementaryCodePoint(codePoint)) + { + // Write second char first to cause IndexOutOfBoundsException + // immediately. + final int cp2 = codePoint - 0x10000; + dst[dstIndex + 1] = (char) ((cp2 % 0x400) + (int) MIN_LOW_SURROGATE); + dst[dstIndex] = (char) ((cp2 / 0x400) + (int) MIN_HIGH_SURROGATE); + result = 2; + } + else + { + dst[dstIndex] = (char) codePoint; + result = 1; + } + return result; + } + + /** + * Return number of 16-bit characters required to represent the given + * code point. + * + * @param codePoint a unicode code point + * + * @return 2 if codePoint >= 0x10000, 1 otherwise. + * + * @since 1.5 + */ + public static int charCount(int codePoint) + { + return + (codePoint >= MIN_SUPPLEMENTARY_CODE_POINT) + ? 2 + : 1; + } + + /** + * Determines whether the specified code point is + * in the range 0x10000 .. 0x10FFFF, i.e. the character is within the Unicode + * supplementary character range. + * + * @param codePoint a Unicode code point + * + * @return <code>true</code> if code point is in supplementary range + * + * @since 1.5 + */ + public static boolean isSupplementaryCodePoint(int codePoint) + { + return codePoint >= MIN_SUPPLEMENTARY_CODE_POINT + && codePoint <= MAX_CODE_POINT; + } + + /** + * Determines whether the specified code point is + * in the range 0x0000 .. 0x10FFFF, i.e. it is a valid Unicode code point. + * + * @param codePoint a Unicode code point + * + * @return <code>true</code> if code point is valid + * + * @since 1.5 + */ + public static boolean isValidCodePoint(int codePoint) + { + return codePoint >= MIN_CODE_POINT && codePoint <= MAX_CODE_POINT; + } + + /** + * Return true if the given character is a high surrogate. + * @param ch the character + * @return true if the character is a high surrogate character + * + * @since 1.5 + */ + public static boolean isHighSurrogate(char ch) + { + return ch >= MIN_HIGH_SURROGATE && ch <= MAX_HIGH_SURROGATE; + } + + /** + * Return true if the given character is a low surrogate. + * @param ch the character + * @return true if the character is a low surrogate character + * + * @since 1.5 + */ + public static boolean isLowSurrogate(char ch) + { + return ch >= MIN_LOW_SURROGATE && ch <= MAX_LOW_SURROGATE; + } + + /** + * Return true if the given characters compose a surrogate pair. + * This is true if the first character is a high surrogate and the + * second character is a low surrogate. + * @param ch1 the first character + * @param ch2 the first character + * @return true if the characters compose a surrogate pair + * + * @since 1.5 + */ + public static boolean isSurrogatePair(char ch1, char ch2) + { + return isHighSurrogate(ch1) && isLowSurrogate(ch2); + } + + /** + * Given a valid surrogate pair, this returns the corresponding + * code point. + * @param high the high character of the pair + * @param low the low character of the pair + * @return the corresponding code point + * + * @since 1.5 + */ + public static int toCodePoint(char high, char low) + { + return ((high - MIN_HIGH_SURROGATE) * 0x400) + + (low - MIN_LOW_SURROGATE) + 0x10000; + } + + /** + * Get the code point at the specified index in the CharSequence. + * This is like CharSequence#charAt(int), but if the character is + * the start of a surrogate pair, and there is a following + * character, and this character completes the pair, then the + * corresponding supplementary code point is returned. Otherwise, + * the character at the index is returned. + * + * @param sequence the CharSequence + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointAt(CharSequence sequence, int index) + { + int len = sequence.length(); + if (index < 0 || index >= len) + throw new IndexOutOfBoundsException(); + char high = sequence.charAt(index); + if (! isHighSurrogate(high) || ++index >= len) + return high; + char low = sequence.charAt(index); + if (! isLowSurrogate(low)) + return high; + return toCodePoint(high, low); + } + + /** + * Get the code point at the specified index in the CharSequence. + * If the character is the start of a surrogate pair, and there is a + * following character, and this character completes the pair, then + * the corresponding supplementary code point is returned. + * Otherwise, the character at the index is returned. + * + * @param chars the character array in which to look + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointAt(char[] chars, int index) + { + return codePointAt(chars, index, chars.length); + } + + /** + * Get the code point at the specified index in the CharSequence. + * If the character is the start of a surrogate pair, and there is a + * following character within the specified range, and this + * character completes the pair, then the corresponding + * supplementary code point is returned. Otherwise, the character + * at the index is returned. + * + * @param chars the character array in which to look + * @param index the index of the codepoint to get, starting at 0 + * @param limit the limit past which characters should not be examined + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= + * limit, or if limit is negative or >= the length of the array + * @since 1.5 + */ + public static int codePointAt(char[] chars, int index, int limit) + { + if (index < 0 || index >= limit || limit < 0 || limit >= chars.length) + throw new IndexOutOfBoundsException(); + char high = chars[index]; + if (! isHighSurrogate(high) || ++index >= limit) + return high; + char low = chars[index]; + if (! isLowSurrogate(low)) + return high; + return toCodePoint(high, low); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(char[], int), but checks the characters at + * <code>index-1</code> and <code>index-2</code> to see if they form + * a supplementary code point. If they do not, the character at + * <code>index-1</code> is returned. + * + * @param chars the character array + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointBefore(char[] chars, int index) + { + return codePointBefore(chars, index, 1); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(char[], int), but checks the characters at + * <code>index-1</code> and <code>index-2</code> to see if they form + * a supplementary code point. If they do not, the character at + * <code>index-1</code> is returned. The start parameter is used to + * limit the range of the array which may be examined. + * + * @param chars the character array + * @param index the index just past the codepoint to get, starting at 0 + * @param start the index before which characters should not be examined + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is > start or > + * the length of the array, or if limit is negative or >= the + * length of the array + * @since 1.5 + */ + public static int codePointBefore(char[] chars, int index, int start) + { + if (index < start || index > chars.length + || start < 0 || start >= chars.length) + throw new IndexOutOfBoundsException(); + --index; + char low = chars[index]; + if (! isLowSurrogate(low) || --index < start) + return low; + char high = chars[index]; + if (! isHighSurrogate(high)) + return low; + return toCodePoint(high, low); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(CharSequence, int), but checks the characters at + * <code>index-1</code> and <code>index-2</code> to see if they form + * a supplementary code point. If they do not, the character at + * <code>index-1</code> is returned. + * + * @param sequence the CharSequence + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public static int codePointBefore(CharSequence sequence, int index) + { + int len = sequence.length(); + if (index < 1 || index > len) + throw new IndexOutOfBoundsException(); + --index; + char low = sequence.charAt(index); + if (! isLowSurrogate(low) || --index < 0) + return low; + char high = sequence.charAt(index); + if (! isHighSurrogate(high)) + return low; + return toCodePoint(high, low); + } +} // class Character diff --git a/gcc-4.2.1/libjava/java/lang/Class.h b/gcc-4.2.1/libjava/java/lang/Class.h new file mode 100644 index 000000000..a884cd6c5 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Class.h @@ -0,0 +1,667 @@ +// Class.h - Header file for java.lang.Class. -*- c++ -*- + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written primary using compiler source and Class.java as guides. +#ifndef __JAVA_LANG_CLASS_H__ +#define __JAVA_LANG_CLASS_H__ + +#pragma interface + +#include <stddef.h> +#include <java/lang/Object.h> +#include <java/lang/String.h> +#include <java/net/URL.h> +#include <java/lang/reflect/Modifier.h> +#include <java/security/ProtectionDomain.h> +#include <java/lang/Package.h> + +// Avoid including SystemClassLoader.h. +extern "Java" +{ + namespace gnu + { + namespace gcj + { + namespace runtime + { + class SystemClassLoader; + } + } + } +} + +// We declare these here to avoid including gcj/cni.h. +extern "C" void _Jv_InitClass (jclass klass); +extern "C" jclass _Jv_NewClassFromInitializer + (const char *class_initializer); +extern "C" void _Jv_RegisterNewClasses (char **classes); +extern "C" void _Jv_RegisterClasses (const jclass *classes); +extern "C" void _Jv_RegisterClasses_Counted (const jclass *classes, + size_t count); + +// This must be predefined with "C" linkage. +extern "C" void *_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, + int meth_idx); +extern "C" void *_Jv_ResolvePoolEntry (jclass this_class, jint index); + +// These are the possible values for the `state' field of the class +// structure. Note that ordering is important here. Whenever the +// state changes, one should notify all waiters of this class. +enum +{ + JV_STATE_NOTHING = 0, // Set by compiler. + + JV_STATE_PRELOADING = 1, // Can do _Jv_FindClass. + + // There is an invariant through libgcj that a class will always be + // at a state greater than or equal to JV_STATE_LOADING when it is + // returned by a class loader to user code. Hence, defineclass.cc + // installs supers before returning a class, C++-ABI-compiled + // classes are created with supers installed, and BC-ABI-compiled + // classes are linked to this state before being returned by their + // class loader. + JV_STATE_LOADING = 3, // Has super installed. + JV_STATE_READ = 4, // Has been completely defined. + JV_STATE_LOADED = 5, // Has Miranda methods defined. + + JV_STATE_COMPILED = 6, // This was a compiled class. + + JV_STATE_PREPARED = 7, // Layout & static init done. + JV_STATE_LINKED = 9, // Strings interned. + + JV_STATE_IN_PROGRESS = 10, // <clinit> running. + + JV_STATE_ERROR = 12, + + JV_STATE_PHANTOM = 13, // Bytecode is missing. In many cases we can + // work around that. If not, throw a + // NoClassDefFoundError. + + JV_STATE_DONE = 14, // Must be last. + + +}; + +struct _Jv_Field; +struct _Jv_VTable; +union _Jv_word; +struct _Jv_ArrayVTable; +class _Jv_Linker; +class _Jv_ExecutionEngine; +class _Jv_CompiledEngine; +class _Jv_IndirectCompiledEngine; +class _Jv_InterpreterEngine; + +#ifdef INTERPRETER +class _Jv_ClassReader; +class _Jv_InterpClass; +class _Jv_InterpMethod; +#endif + +struct _Jv_Constants +{ + jint size; + jbyte *tags; + _Jv_word *data; +}; + +struct _Jv_Method +{ + // Method name. + _Jv_Utf8Const *name; + // Method signature. + _Jv_Utf8Const *signature; + // Access flags. + _Jv_ushort accflags; + // Method's index in the vtable. + _Jv_ushort index; + // Pointer to underlying function. + void *ncode; + // NULL-terminated list of exception class names; can be NULL if + // there are none such. + _Jv_Utf8Const **throws; + + _Jv_Method *getNextMethod () + { return this + 1; } +}; + +// The table used to resolve interface calls. +struct _Jv_IDispatchTable +{ + // Index into interface's ioffsets. + jshort iindex; + jshort itable_length; + // Class Interface dispatch table. + void *itable[0]; +}; + +// Used by _Jv_Linker::get_interfaces () +struct _Jv_ifaces +{ + jclass *list; + jshort len; + jshort count; +}; + +struct _Jv_MethodSymbol +{ + _Jv_Utf8Const *class_name; + _Jv_Utf8Const *name; + _Jv_Utf8Const *signature; +}; + +struct _Jv_OffsetTable +{ + jint state; + jint offsets[]; +}; + +struct _Jv_AddressTable +{ + jint state; + void *addresses[]; +}; + +struct _Jv_CatchClass +{ + java::lang::Class **address; + _Jv_Utf8Const *classname; +}; + +// Possible values for the assertion_code field in the type assertion table. +enum +{ + JV_ASSERT_END_OF_TABLE = 0, + JV_ASSERT_TYPES_COMPATIBLE = 1, + JV_ASSERT_IS_INSTANTIABLE = 2 +}; + +// Entry in the type assertion table, used to validate type constraints +// for binary compatibility. +struct _Jv_TypeAssertion +{ + jint assertion_code; + _Jv_Utf8Const *op1; + _Jv_Utf8Const *op2; +}; + +#define JV_PRIMITIVE_VTABLE ((_Jv_VTable *) -1) + +#define JV_CLASS(Obj) ((jclass) (*(_Jv_VTable **) Obj)->clas) + +// Forward declarations for friends of java::lang::Class + +// Friend functions implemented in natClass.cc. +_Jv_Method *_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature); +jboolean _Jv_IsAssignableFrom (jclass, jclass); +jboolean _Jv_IsAssignableFromSlow (jclass, jclass); +jboolean _Jv_InterfaceAssignableFrom (jclass, jclass); + +_Jv_Method* _Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*, jclass * = NULL); +jfieldID JvGetFirstInstanceField (jclass); +jint JvNumInstanceFields (jclass); +jfieldID JvGetFirstStaticField (jclass); +jint JvNumStaticFields (jclass); + +jobject _Jv_AllocObject (jclass); +void *_Jv_AllocObj (jint, jclass); +void *_Jv_AllocPtrFreeObj (jint, jclass); +void *_Jv_AllocArray (jint, jclass); + +bool _Jv_getInterfaceMethod(jclass, jclass&, int&, + const _Jv_Utf8Const*, + const _Jv_Utf8Const*); + +jobject _Jv_JNI_ToReflectedField (_Jv_JNIEnv *, jclass, jfieldID, + jboolean); +jobject _Jv_JNI_ToReflectedMethod (_Jv_JNIEnv *, jclass, jmethodID, + jboolean); +jfieldID _Jv_FromReflectedField (java::lang::reflect::Field *); + +jmethodID _Jv_FromReflectedMethod (java::lang::reflect::Method *); +jmethodID _Jv_FromReflectedConstructor (java::lang::reflect::Constructor *); +jint JvNumMethods (jclass); +jmethodID JvGetFirstMethod (jclass); +_Jv_Utf8Const *_Jv_GetClassNameUtf8 (jclass); + +#ifdef INTERPRETER +// Finds a desired interpreter method in the given class or NULL if not found +class _Jv_MethodBase; +_Jv_MethodBase *_Jv_FindInterpreterMethod (jclass, jmethodID); +#endif + +// Friend classes and functions to implement the ClassLoader +class java::lang::ClassLoader; +class java::lang::VMClassLoader; + +class java::io::ObjectOutputStream; +class java::io::ObjectInputStream; +class java::io::ObjectStreamClass; + +void _Jv_RegisterClassHookDefault (jclass klass); +void _Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); +void _Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*); +void _Jv_UnregisterClass (jclass); +jclass _Jv_FindClassNoException (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); +jclass _Jv_FindClass (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); +jclass _Jv_FindClassInCache (_Jv_Utf8Const *name); +jclass _Jv_PopClass (void); +void _Jv_PushClass (jclass k); +void _Jv_NewArrayClass (jclass element, + java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable = 0); +jclass _Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader); +void _Jv_InitNewClassFields (jclass klass); + +// Friend functions and classes in prims.cc +void _Jv_InitPrimClass (jclass, const char *, char, int); +jstring _Jv_GetMethodString (jclass, _Jv_Method *, jclass = NULL); + +jboolean _Jv_CheckAccess (jclass self_klass, jclass other_klass, + jint flags); +jclass _Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader); + +jboolean _Jv_IsInterpretedClass (jclass); +jboolean _Jv_IsBinaryCompatibilityABI (jclass); + +jboolean _Jv_IsPhantomClass (jclass); + +void _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *); + +#ifdef INTERPRETER +void _Jv_InitField (jobject, jclass, int); +#endif + +class _Jv_StackTrace; +class _Jv_BytecodeVerifier; +class java::io::VMObjectStreamClass; + +void _Jv_sharedlib_register_hook (jclass klass); + + +class java::lang::Class : public java::lang::Object +{ +public: + static jclass forName (jstring className, jboolean initialize, + java::lang::ClassLoader *loader); + static jclass forName (jstring className); + JArray<jclass> *getClasses (void); + + java::lang::ClassLoader *getClassLoader (void); +private: + java::lang::ClassLoader *getClassLoader (jclass caller); +public: + // This is an internal method that circumvents the usual security + // checks when getting the class loader. + java::lang::ClassLoader *getClassLoaderInternal (void) + { + return loader; + } + + java::lang::reflect::Constructor *getConstructor (JArray<jclass> *); + JArray<java::lang::reflect::Constructor *> *getConstructors (void); + java::lang::reflect::Constructor *getDeclaredConstructor (JArray<jclass> *); + JArray<java::lang::reflect::Constructor *> *getDeclaredConstructors (jboolean); + java::lang::reflect::Field *getDeclaredField (jstring); + JArray<java::lang::reflect::Field *> *getDeclaredFields (); + JArray<java::lang::reflect::Field *> *getDeclaredFields (jboolean); + java::lang::reflect::Method *getDeclaredMethod (jstring, JArray<jclass> *); + JArray<java::lang::reflect::Method *> *getDeclaredMethods (void); + + JArray<jclass> *getDeclaredClasses (void); + JArray<jclass> *getDeclaredClasses (jboolean); + jclass getDeclaringClass (void); + + java::lang::reflect::Field *getField (jstring); +private: + JArray<java::lang::reflect::Field *> internalGetFields (); + java::lang::reflect::Field *getField (jstring, jint); + jint _getMethods (JArray<java::lang::reflect::Method *> *result, + jint offset); + java::lang::reflect::Field *getPrivateField (jstring); + java::lang::reflect::Method *getPrivateMethod (jstring, JArray<jclass> *); + java::security::ProtectionDomain *getProtectionDomain0 (); + + java::lang::reflect::Method *_getMethod (jstring, JArray<jclass> *); + java::lang::reflect::Method *_getDeclaredMethod (jstring, JArray<jclass> *); + +public: + JArray<java::lang::reflect::Field *> *getFields (void); + + JArray<jclass> *getInterfaces (void); + + void getSignature (java::lang::StringBuffer *buffer); + static jstring getSignature (JArray<jclass> *, jboolean is_constructor); + JArray<java::lang::reflect::Method *> *getMethods (void); + + inline jint getModifiers (void) + { + return accflags & java::lang::reflect::Modifier::ALL_FLAGS; + } + + jstring getName (void); + + java::net::URL *getResource (jstring resourceName); + java::io::InputStream *getResourceAsStream (jstring resourceName); + JArray<jobject> *getSigners (void); + void setSigners(JArray<jobject> *); + + inline jclass getSuperclass (void) + { + return superclass; + } + + inline jclass getInterface (jint n) + { + return interfaces[n]; + } + + inline jboolean isArray (void) + { + return name->first() == '['; + } + + inline jclass getComponentType (void) + { + return isArray () ? element_type : 0; + } + + jboolean isAssignableFrom (jclass cls); + jboolean isInstance (jobject obj); + + inline jboolean isInterface (void) + { + return (accflags & java::lang::reflect::Modifier::INTERFACE) != 0; + } + + inline jboolean isPrimitive (void) + { + return vtable == JV_PRIMITIVE_VTABLE; + } + + jobject newInstance (void); + java::security::ProtectionDomain *getProtectionDomain (void); + java::lang::Package *getPackage (void); + jstring toString (void); + jboolean desiredAssertionStatus (void); + + JArray<java::lang::reflect::TypeVariable *> *getTypeParameters (void); + + java::lang::Class *getEnclosingClass (void); + java::lang::reflect::Constructor *getEnclosingConstructor (void); + java::lang::reflect::Method *getEnclosingMethod (void); + jboolean isEnum (void); + + // FIXME: this probably shouldn't be public. + jint size (void) + { + return size_in_bytes; + } + + // The index of the first method we declare ourself (as opposed to + // inheriting). + inline jint firstMethodIndex (void) + { + return vtable_method_count - method_count; + } + + // finalization + void finalize (); + + // This constructor is used to create Class object for the primitive + // types. See prims.cc. + Class (); + + static java::lang::Class class$; + +private: + + void memberAccessCheck (jint flags); + + void initializeClass (void); + + static jstring getPackagePortion (jstring); + + void set_state (jint nstate) + { + state = nstate; + notifyAll (); + } + + // Friend functions implemented in natClass.cc. + friend _Jv_Method *::_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature); + friend jboolean (::_Jv_IsAssignableFrom) (jclass, jclass); + friend jboolean (::_Jv_IsAssignableFromSlow) (jclass, jclass); + friend jboolean (::_Jv_InterfaceAssignableFrom) (jclass, jclass); + friend void *::_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, + int method_idx); + + friend void ::_Jv_InitClass (jclass klass); + friend java::lang::Class* ::_Jv_NewClassFromInitializer (const char *class_initializer); + friend void _Jv_RegisterNewClasses (void **classes); + + friend _Jv_Method* ::_Jv_LookupDeclaredMethod (jclass, _Jv_Utf8Const *, + _Jv_Utf8Const*, jclass *); + friend jfieldID (::JvGetFirstInstanceField) (jclass); + friend jint (::JvNumInstanceFields) (jclass); + friend jfieldID (::JvGetFirstStaticField) (jclass); + friend jint (::JvNumStaticFields) (jclass); + + friend jobject (::_Jv_AllocObject) (jclass); + friend void *::_Jv_AllocObj (jint, jclass); + friend void *::_Jv_AllocPtrFreeObj (jint, jclass); + friend void *::_Jv_AllocArray (jint, jclass); + + friend jobject (::_Jv_JNI_ToReflectedField) (_Jv_JNIEnv *, jclass, jfieldID, + jboolean); + friend jobject (::_Jv_JNI_ToReflectedMethod) (_Jv_JNIEnv *, jclass, jmethodID, + jboolean); + friend jfieldID (::_Jv_FromReflectedField) (java::lang::reflect::Field *); + + friend jmethodID (::_Jv_FromReflectedMethod) (java::lang::reflect::Method *); + friend jmethodID (::_Jv_FromReflectedConstructor) (java::lang::reflect::Constructor *); + friend jint (::JvNumMethods) (jclass); + friend jmethodID (::JvGetFirstMethod) (jclass); + friend _Jv_Utf8Const *::_Jv_GetClassNameUtf8 (jclass); +#ifdef INTERPRETER + friend _Jv_MethodBase *(::_Jv_FindInterpreterMethod) (jclass klass, + jmethodID desired_method); +#endif + + // Friends classes and functions to implement the ClassLoader + friend class java::lang::ClassLoader; + friend class java::lang::VMClassLoader; + + friend class java::io::ObjectOutputStream; + friend class java::io::ObjectInputStream; + friend class java::io::ObjectStreamClass; + + friend void ::_Jv_RegisterClasses (const jclass *classes); + friend void ::_Jv_RegisterClasses_Counted (const jclass *classes, + size_t count); + friend void ::_Jv_RegisterClassHookDefault (jclass klass); + friend void ::_Jv_RegisterInitiatingLoader (jclass,java::lang::ClassLoader*); + friend void ::_Jv_UnregisterInitiatingLoader (jclass,java::lang::ClassLoader*); + friend void ::_Jv_UnregisterClass (jclass); + friend jclass (::_Jv_FindClassNoException) (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass (::_Jv_FindClass) (_Jv_Utf8Const *name, + java::lang::ClassLoader *loader); + friend jclass (::_Jv_FindClassInCache) (_Jv_Utf8Const *name); + friend jclass (::_Jv_PopClass) (void); + friend void ::_Jv_PushClass (jclass k); + friend void ::_Jv_NewArrayClass (jclass element, + java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable); + friend jclass (::_Jv_NewClass) (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader); + friend void ::_Jv_InitNewClassFields (jclass klass); + + // in prims.cc + friend void ::_Jv_InitPrimClass (jclass, const char *, char, int); + + friend jstring (::_Jv_GetMethodString) (jclass, _Jv_Method *, jclass); + + friend jboolean (::_Jv_CheckAccess) (jclass self_klass, jclass other_klass, + jint flags); + + friend bool (::_Jv_getInterfaceMethod) (jclass, jclass&, int&, + const _Jv_Utf8Const*, + const _Jv_Utf8Const*); + + friend jclass (::_Jv_GetArrayClass) (jclass klass, + java::lang::ClassLoader *loader); + + friend jboolean (::_Jv_IsInterpretedClass) (jclass); + friend jboolean (::_Jv_IsBinaryCompatibilityABI) (jclass); + + friend jboolean (::_Jv_IsPhantomClass) (jclass); + +#ifdef INTERPRETER + friend void ::_Jv_InitField (jobject, jclass, int); + + friend class ::_Jv_ClassReader; + friend class ::_Jv_InterpClass; + friend class ::_Jv_InterpMethod; +#endif + friend class ::_Jv_StackTrace; + +#ifdef JV_MARKOBJ_DECL + friend JV_MARKOBJ_DECL; +#endif + + friend class ::_Jv_BytecodeVerifier; + friend class java::io::VMObjectStreamClass; + + friend class ::_Jv_Linker; + friend class ::_Jv_ExecutionEngine; + friend class ::_Jv_CompiledEngine; + friend class ::_Jv_IndirectCompiledEngine; + friend class ::_Jv_InterpreterEngine; + + friend void ::_Jv_sharedlib_register_hook (jclass klass); + + friend void *::_Jv_ResolvePoolEntry (jclass this_class, jint index); + + friend void ::_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *); + + // Chain for class pool. This also doubles as the ABI version + // number. It is only used for this purpose at class registration + // time, and only for precompiled classes. + jclass next_or_version; + // Name of class. + _Jv_Utf8Const *name; + // Access flags for class. + _Jv_ushort accflags; + // The superclass, or null for Object. + jclass superclass; + // Class constants. + _Jv_Constants constants; + // Methods. If this is an array class, then this field holds a + // pointer to the element type. + union + { + _Jv_Method *methods; + jclass element_type; + }; + // Number of methods. If this class is primitive, this holds the + // character used to represent this type in a signature. + jshort method_count; + // Number of methods in the vtable. + jshort vtable_method_count; + // The fields. + _Jv_Field *fields; + // Size of instance fields, in bytes. + jint size_in_bytes; + // Total number of fields (instance and static). + jshort field_count; + // Number of static fields. + jshort static_field_count; + // The vtbl for all objects of this class. + _Jv_VTable *vtable; + // Virtual method offset table. + _Jv_OffsetTable *otable; + // Offset table symbols. + _Jv_MethodSymbol *otable_syms; + // Address table + _Jv_AddressTable *atable; + _Jv_MethodSymbol *atable_syms; + // Interface table + _Jv_AddressTable *itable; + _Jv_MethodSymbol *itable_syms; + _Jv_CatchClass *catch_classes; + // Interfaces implemented by this class. + jclass *interfaces; + // The class loader for this class. + java::lang::ClassLoader *loader; + // Number of interfaces. + jshort interface_count; + // State of this class. + jbyte state; + // The thread which has locked this class. Used during class + // initialization. + java::lang::Thread *thread; + // How many levels of "extends" this class is removed from Object. + jshort depth; + // Vector of this class's superclasses, ordered by decreasing depth. + jclass *ancestors; + // In a regular class, this field points to the Class Interface Dispatch + // Table. In an interface, it points to the ioffsets table. + union + { + _Jv_IDispatchTable *idt; + jshort *ioffsets; + }; + // Pointer to the class that represents an array of this class. + jclass arrayclass; + // Security Domain to which this class belongs (or null). + java::security::ProtectionDomain *protectionDomain; + // Pointer to the type assertion table for this class. + _Jv_TypeAssertion *assertion_table; + // Signers of this class (or null). + JArray<jobject> *hack_signers; + // Used by Jv_PopClass and _Jv_PushClass to communicate with StackTrace. + jclass chain; + // Additional data, specific to the generator (JIT, native, + // interpreter) of this class. + void *aux_info; + // Execution engine. + _Jv_ExecutionEngine *engine; +}; + +// Inline functions that are friends of java::lang::Class + +inline void _Jv_InitClass (jclass klass) +{ + if (__builtin_expect (klass->state == JV_STATE_DONE, true)) + return; + klass->initializeClass (); +} + +// Return array class corresponding to element type KLASS, creating it if +// necessary. +inline jclass +_Jv_GetArrayClass (jclass klass, java::lang::ClassLoader *loader) +{ + extern void _Jv_NewArrayClass (jclass element, + java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable = 0); + if (__builtin_expect (!klass->arrayclass, false)) + _Jv_NewArrayClass (klass, loader); + return klass->arrayclass; +} + +#endif /* __JAVA_LANG_CLASS_H__ */ diff --git a/gcc-4.2.1/libjava/java/lang/Class.java b/gcc-4.2.1/libjava/java/lang/Class.java new file mode 100644 index 000000000..75819e868 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Class.java @@ -0,0 +1,1032 @@ +/* Class.java -- Representation of a Java class. + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.InputStream; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.GenericDeclaration; +import java.lang.reflect.Member; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.lang.reflect.TypeVariable; +import java.net.URL; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; + +/** + * A Class represents a Java type. There will never be multiple Class + * objects with identical names and ClassLoaders. Primitive types, array + * types, and void also have a Class object. + * + * <p>Arrays with identical type and number of dimensions share the same class. + * The array class ClassLoader is the same as the ClassLoader of the element + * type of the array (which can be null to indicate the bootstrap classloader). + * The name of an array class is <code>[<signature format>;</code>. + * <p> For example, + * String[]'s class is <code>[Ljava.lang.String;</code>. boolean, byte, + * short, char, int, long, float and double have the "type name" of + * Z,B,S,C,I,J,F,D for the purposes of array classes. If it's a + * multidimensioned array, the same principle applies: + * <code>int[][][]</code> == <code>[[[I</code>. + * + * <p>There is no public constructor - Class objects are obtained only through + * the virtual machine, as defined in ClassLoaders. + * + * @serialData Class objects serialize specially: + * <code>TC_CLASS ClassDescriptor</code>. For more serialization information, + * see {@link ObjectStreamClass}. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@cygnus.com) + * @since 1.0 + * @see ClassLoader + */ +public final class Class implements Type, GenericDeclaration, Serializable +{ + /** + * Class is non-instantiable from Java code; only the VM can create + * instances of this class. + */ + private Class () + { + } + + // Initialize the class. + private native void initializeClass (); + + // finalization + protected native void finalize () throws Throwable; + + /** + * Use the classloader of the current class to load, link, and initialize + * a class. This is equivalent to your code calling + * <code>Class.forName(name, true, getClass().getClassLoader())</code>. + * + * @param name the name of the class to find + * @return the Class object representing the class + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + */ + public static native Class forName (String className) + throws ClassNotFoundException; + + // A private internal method that is called by compiler-generated code. + private static Class forName (String className, Class caller) + throws ClassNotFoundException + { + return forName(className, true, caller.getClassLoaderInternal()); + } + + + /** + * Use the specified classloader to load and link a class. If the loader + * is null, this uses the bootstrap class loader (provide the security + * check succeeds). Unfortunately, this method cannot be used to obtain + * the Class objects for primitive types or for void, you have to use + * the fields in the appropriate java.lang wrapper classes. + * + * <p>Calls <code>classloader.loadclass(name, initialize)</code>. + * + * @param name the name of the class to find + * @param initialize whether or not to initialize the class at this time + * @param classloader the classloader to use to find the class; null means + * to use the bootstrap class loader + * @throws ClassNotFoundException if the class was not found by the + * classloader + * @throws LinkageError if linking the class fails + * @throws ExceptionInInitializerError if the class loads, but an exception + * occurs during initialization + * @throws SecurityException if the <code>classloader</code> argument + * is <code>null</code> and the caller does not have the + * <code>RuntimePermission("getClassLoader")</code> permission + * @see ClassLoader + * @since 1.2 + */ + public static native Class forName (String className, boolean initialize, + ClassLoader loader) + throws ClassNotFoundException; + + /** + * Get all the public member classes and interfaces declared in this + * class or inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all public member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class[] getClasses() + { + memberAccessCheck(Member.PUBLIC); + return internalGetClasses(); + } + + /** + * Like <code>getClasses()</code> but without the security checks. + */ + private Class[] internalGetClasses() + { + ArrayList list = new ArrayList(); + list.addAll(Arrays.asList(getDeclaredClasses(true))); + Class superClass = getSuperclass(); + if (superClass != null) + list.addAll(Arrays.asList(superClass.internalGetClasses())); + return (Class[])list.toArray(new Class[list.size()]); + } + + /** + * Get the ClassLoader that loaded this class. If the class was loaded + * by the bootstrap classloader, this method will return null. + * If there is a security manager, and the caller's class loader is not + * an ancestor of the requested one, a security check of + * <code>RuntimePermission("getClassLoader")</code> + * must first succeed. Primitive types and void return null. + * + * @return the ClassLoader that loaded this class + * @throws SecurityException if the security check fails + * @see ClassLoader + * @see RuntimePermission + */ + public native ClassLoader getClassLoader (); + + // A private internal method that is called by compiler-generated code. + private final native ClassLoader getClassLoader (Class caller); + + /** + * Internal method that circumvents the usual security checks when + * getting the class loader. + */ + private native ClassLoader getClassLoaderInternal (); + + /** + * If this is an array, get the Class representing the type of array. + * Examples: "[[Ljava.lang.String;" would return "[Ljava.lang.String;", and + * calling getComponentType on that would give "java.lang.String". If + * this is not an array, returns null. + * + * @return the array type of this class, or null + * @see Array + * @since 1.1 + */ + public native Class getComponentType (); + + /** + * Get a public constructor declared in this class. If the constructor takes + * no argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getConstructors() + * @since 1.1 + */ + public native Constructor getConstructor(Class[] args) + throws NoSuchMethodException; + + /** + * Get all the public constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with <code>checkMemberAccess(this, Member.PUBLIC)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @return all public constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor[] getConstructors() + { + memberAccessCheck(Member.PUBLIC); + return getDeclaredConstructors(true); + } + + /** + * Get a constructor declared in this class. If the constructor takes no + * argument, an array of zero elements and null are equivalent for the + * types argument. A security check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param types the type of each parameter + * @return the constructor + * @throws NoSuchMethodException if the constructor does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredConstructors() + * @since 1.1 + */ + public native Constructor getDeclaredConstructor(Class[] args) + throws NoSuchMethodException; + + /** + * Get all the declared member classes and interfaces in this class, but + * not those inherited from superclasses. This returns an array of length + * 0 if there are no member classes, including for primitive types. A + * security check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all declared member classes in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Class[] getDeclaredClasses() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredClasses(false); + } + + native Class[] getDeclaredClasses (boolean publicOnly); + + /** + * Get all the declared constructors of this class. This returns an array of + * length 0 if there are no constructors, including for primitive types, + * arrays, and interfaces. It does, however, include the default + * constructor if one was supplied by the compiler. A security check may + * be performed, with <code>checkMemberAccess(this, Member.DECLARED)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @return all constructors in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Constructor[] getDeclaredConstructors() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredConstructors(false); + } + + native Constructor[] getDeclaredConstructors (boolean publicOnly); + + /** + * Get a field declared in this class, where name is its simple name. The + * implicit length field of arrays is not available. A security check may + * be performed, with <code>checkMemberAccess(this, Member.DECLARED)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @param name the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredFields() + * @since 1.1 + */ + public native Field getDeclaredField(String fieldName) + throws NoSuchFieldException; + + /** + * Get all the declared fields in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all declared fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getDeclaredFields() + { + memberAccessCheck(Member.DECLARED); + return getDeclaredFields(false); + } + + native Field[] getDeclaredFields (boolean publicOnly); + + private native Method _getDeclaredMethod(String methodName, Class[] args); + + /** + * Get a method declared in this class, where name is its simple name. The + * implicit methods of Object are not available from arrays or interfaces. + * Constructors (named "<init>" in the class file) and class initializers + * (name "<clinit>") are not available. The Virtual Machine allows + * multiple methods with the same signature but differing return types; in + * such a case the most specific return types are favored, then the final + * choice is arbitrary. If the method takes no argument, an array of zero + * elements and null are equivalent for the types argument. A security + * check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getDeclaredMethods() + * @since 1.1 + */ + public Method getDeclaredMethod(String methodName, Class[] args) + throws NoSuchMethodException + { + memberAccessCheck(Member.DECLARED); + + if ("<init>".equals(methodName) || "<clinit>".equals(methodName)) + throw new NoSuchMethodException(methodName); + + Method match = _getDeclaredMethod(methodName, args); + if (match == null) + throw new NoSuchMethodException(methodName); + return match; + } + + /** + * Get all the declared methods in this class, but not those inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does include the implicit methods of + * arrays and interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * <code>checkMemberAccess(this, Member.DECLARED)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all declared methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public native Method[] getDeclaredMethods(); + + /** + * If this is a nested or inner class, return the class that declared it. + * If not, return null. + * + * @return the declaring class of this class + * @since 1.1 + */ + // This is marked as unimplemented in the JCL book. + public native Class getDeclaringClass (); + + private native Field getField (String fieldName, int hash) + throws NoSuchFieldException; + + /** + * Get a public field declared or inherited in this class, where name is + * its simple name. If the class contains multiple accessible fields by + * that name, an arbitrary one is returned. The implicit length field of + * arrays is not available. A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param fieldName the name of the field + * @return the field + * @throws NoSuchFieldException if the field does not exist + * @throws SecurityException if the security check fails + * @see #getFields() + * @since 1.1 + */ + public Field getField(String fieldName) + throws NoSuchFieldException + { + memberAccessCheck(Member.PUBLIC); + Field field = getField(fieldName, fieldName.hashCode()); + if (field == null) + throw new NoSuchFieldException(fieldName); + return field; + } + + /** + * Get all the public fields declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no fields, + * including for primitive types. This does not return the implicit length + * field of arrays. A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all public fields in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public Field[] getFields() + { + memberAccessCheck(Member.PUBLIC); + return internalGetFields(); + } + + /** + * Like <code>getFields()</code> but without the security checks. + */ + private Field[] internalGetFields() + { + HashSet set = new HashSet(); + set.addAll(Arrays.asList(getDeclaredFields(true))); + Class[] interfaces = getInterfaces(); + for (int i = 0; i < interfaces.length; i++) + set.addAll(Arrays.asList(interfaces[i].internalGetFields())); + Class superClass = getSuperclass(); + if (superClass != null) + set.addAll(Arrays.asList(superClass.internalGetFields())); + return (Field[])set.toArray(new Field[set.size()]); + } + + /** + * Returns the <code>Package</code> in which this class is defined + * Returns null when this information is not available from the + * classloader of this class. + * + * @return the package for this class, if it is available + * @since 1.2 + */ + public Package getPackage() + { + ClassLoader cl = getClassLoaderInternal(); + if (cl != null) + return cl.getPackage(getPackagePortion(getName())); + else + return VMClassLoader.getPackage(getPackagePortion(getName())); + } + + /** + * Get the interfaces this class <em>directly</em> implements, in the + * order that they were declared. This returns an empty array, not null, + * for Object, primitives, void, and classes or interfaces with no direct + * superinterface. Array types return Cloneable and Serializable. + * + * @return the interfaces this class directly implements + */ + public native Class[] getInterfaces (); + + private final native void getSignature(StringBuffer buffer); + private static final native String getSignature(Class[] args, + boolean is_construtor); + + public native Method _getMethod(String methodName, Class[] args); + + /** + * Get a public method declared or inherited in this class, where name is + * its simple name. The implicit methods of Object are not available from + * interfaces. Constructors (named "<init>" in the class file) and class + * initializers (name "<clinit>") are not available. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types, and the class can inherit multiple methods of the same + * return type; in such a case the most specific return types are favored, + * then the final choice is arbitrary. If the method takes no argument, an + * array of zero elements and null are equivalent for the types argument. + * A security check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @param methodName the name of the method + * @param types the type of each parameter + * @return the method + * @throws NoSuchMethodException if the method does not exist + * @throws SecurityException if the security check fails + * @see #getMethods() + * @since 1.1 + */ + public Method getMethod(String methodName, Class[] args) + throws NoSuchMethodException + { + memberAccessCheck(Member.PUBLIC); + + if ("<init>".equals(methodName) || "<clinit>".equals(methodName)) + throw new NoSuchMethodException(methodName); + + Method method = _getMethod(methodName, args); + if (method == null) + throw new NoSuchMethodException(methodName); + return method; + } + + private native int _getMethods (Method[] result, int offset); + + /** + * Get all the public methods declared in this class or inherited from + * superclasses. This returns an array of length 0 if there are no methods, + * including for primitive types. This does not include the implicit + * methods of interfaces which mirror methods of Object, nor does it + * include constructors or the class initialization methods. The Virtual + * Machine allows multiple methods with the same signature but differing + * return types; all such methods are in the returned array. A security + * check may be performed, with + * <code>checkMemberAccess(this, Member.PUBLIC)</code> as well as + * <code>checkPackageAccess</code> both having to succeed. + * + * @return all public methods in this class + * @throws SecurityException if the security check fails + * @since 1.1 + */ + public native Method[] getMethods(); + + /** + * Get the modifiers of this class. These can be decoded using Modifier, + * and is limited to one of public, protected, or private, and any of + * final, static, abstract, or interface. An array class has the same + * public, protected, or private modifier as its component type, and is + * marked final but not an interface. Primitive types and void are marked + * public and final, but not an interface. + * + * @return the modifiers of this class + * @see Modifer + * @since 1.1 + */ + public native int getModifiers (); + + /** + * Get the name of this class, separated by dots for package separators. + * If the class represents a primitive type, or void, then the + * name of the type as it appears in the Java programming language + * is returned. For instance, <code>Byte.TYPE.getName()</code> + * returns "byte". + * + * Arrays are specially encoded as shown on this table. + * <pre> + * array type [<em>element type</em> + * (note that the element type is encoded per + * this table) + * boolean Z + * byte B + * char C + * short S + * int I + * long J + * float F + * double D + * void V + * class or interface, alone: <dotted name> + * class or interface, as element type: L<dotted name>; + * </pre> + * + * @return the name of this class + */ + public native String getName (); + + /** + * Get a resource URL using this class's package using the + * getClassLoader().getResource() method. If this class was loaded using + * the system classloader, ClassLoader.getSystemResource() is used instead. + * + * <p>If the name you supply is absolute (it starts with a <code>/</code>), + * then the leading <code>/</code> is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * <code>.</code>'s are replaced with <code>/</code>. + * + * <p>The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return the URL to the resource + * @throws NullPointerException if name is null + * @since 1.1 + */ + public URL getResource(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoaderInternal(); + if (loader == null) + return ClassLoader.getSystemResource(name); + return loader.getResource(name); + } + + /** + * Get a resource using this class's package using the + * getClassLoader().getResourceAsStream() method. If this class was loaded + * using the system classloader, ClassLoader.getSystemResource() is used + * instead. + * + * <p>If the name you supply is absolute (it starts with a <code>/</code>), + * then the leading <code>/</code> is removed and it is passed on to + * getResource(). If it is relative, the package name is prepended, and + * <code>.</code>'s are replaced with <code>/</code>. + * + * <p>The URL returned is system- and classloader-dependent, and could + * change across implementations. + * + * @param resourceName the name of the resource, generally a path + * @return an InputStream with the contents of the resource in it, or null + * @throws NullPointerException if name is null + * @since 1.1 + */ + public InputStream getResourceAsStream(String resourceName) + { + String name = resourcePath(resourceName); + ClassLoader loader = getClassLoaderInternal(); + if (loader == null) + return ClassLoader.getSystemResourceAsStream(name); + return loader.getResourceAsStream(name); + } + + private String resourcePath(String resourceName) + { + if (resourceName.length() > 0) + { + if (resourceName.charAt(0) != '/') + { + String pkg = getPackagePortion(getName()); + if (pkg.length() > 0) + resourceName = pkg.replace('.','/') + '/' + resourceName; + } + else + { + resourceName = resourceName.substring(1); + } + } + return resourceName; + } + + /** + * Get the signers of this class. This returns null if there are no signers, + * such as for primitive types or void. + * + * @return the signers of this class + * @since 1.1 + */ + public native Object[] getSigners (); + + /** + * Set the signers of this class. + * + * @param signers the signers of this class + */ + native void setSigners(Object[] signers); + + /** + * Get the direct superclass of this class. If this is an interface, + * Object, a primitive type, or void, it will return null. If this is an + * array type, it will return Object. + * + * @return the direct superclass of this class + */ + public native Class getSuperclass (); + + /** + * Return whether this class is an array type. + * + * @return whether this class is an array type + * @since 1.1 + */ + public native boolean isArray (); + + /** + * Discover whether an instance of the Class parameter would be an + * instance of this Class as well. Think of doing + * <code>isInstance(c.newInstance())</code> or even + * <code>c.newInstance() instanceof (this class)</code>. While this + * checks widening conversions for objects, it must be exact for primitive + * types. + * + * @param c the class to check + * @return whether an instance of c would be an instance of this class + * as well + * @throws NullPointerException if c is null + * @since 1.1 + */ + public native boolean isAssignableFrom (Class c); + + /** + * Discover whether an Object is an instance of this Class. Think of it + * as almost like <code>o instanceof (this class)</code>. + * + * @param o the Object to check + * @return whether o is an instance of this class + * @since 1.1 + */ + public native boolean isInstance (Object o); + + /** + * Check whether this class is an interface or not. Array types are not + * interfaces. + * + * @return whether this class is an interface or not + */ + public native boolean isInterface (); + + /** + * Return whether this class is a primitive type. A primitive type class + * is a class representing a kind of "placeholder" for the various + * primitive types, or void. You can access the various primitive type + * classes through java.lang.Boolean.TYPE, java.lang.Integer.TYPE, etc., + * or through boolean.class, int.class, etc. + * + * @return whether this class is a primitive type + * @see Boolean#TYPE + * @see Byte#TYPE + * @see Character#TYPE + * @see Short#TYPE + * @see Integer#TYPE + * @see Long#TYPE + * @see Float#TYPE + * @see Double#TYPE + * @see Void#TYPE + * @since 1.1 + */ + public native boolean isPrimitive (); + + /** + * Get a new instance of this class by calling the no-argument constructor. + * The class is initialized if it has not been already. A security check + * may be performed, with <code>checkMemberAccess(this, Member.PUBLIC)</code> + * as well as <code>checkPackageAccess</code> both having to succeed. + * + * @return a new instance of this class + * @throws InstantiationException if there is not a no-arg constructor + * for this class, including interfaces, abstract classes, arrays, + * primitive types, and void; or if an exception occurred during + * the constructor + * @throws IllegalAccessException if you are not allowed to access the + * no-arg constructor because of scoping reasons + * @throws SecurityException if the security check fails + * @throws ExceptionInInitializerError if class initialization caused by + * this call fails with an exception + */ + public native Object newInstance () + throws InstantiationException, IllegalAccessException; + + // We need a native method to retrieve the protection domain, because we + // can't add fields to java.lang.Class that are accessible from Java. + private native ProtectionDomain getProtectionDomain0(); + + /** + * Returns the protection domain of this class. If the classloader did not + * record the protection domain when creating this class the unknown + * protection domain is returned which has a <code>null</code> code source + * and all permissions. A security check may be performed, with + * <code>RuntimePermission("getProtectionDomain")</code>. + * + * @return the protection domain + * @throws SecurityException if the security manager exists and the caller + * does not have <code>RuntimePermission("getProtectionDomain")</code>. + * @see RuntimePermission + * @since 1.2 + */ + public ProtectionDomain getProtectionDomain() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(VMClassLoader.protectionDomainPermission); + + ProtectionDomain protectionDomain = getProtectionDomain0(); + + if (protectionDomain == null) + return VMClassLoader.unknownProtectionDomain; + else + return protectionDomain; + } + + /** + * Return the human-readable form of this Object. For an object, this + * is either "interface " or "class " followed by <code>getName()</code>, + * for primitive types and void it is just <code>getName()</code>. + * + * @return the human-readable form of this Object + */ + public String toString() + { + if (isPrimitive()) + return getName(); + return (isInterface() ? "interface " : "class ") + getName(); + } + + /** + * Returns the desired assertion status of this class, if it were to be + * initialized at this moment. The class assertion status, if set, is + * returned; the backup is the default package status; then if there is + * a class loader, that default is returned; and finally the system default + * is returned. This method seldom needs calling in user code, but exists + * for compilers to implement the assert statement. Note that there is no + * guarantee that the result of this method matches the class's actual + * assertion status. + * + * @return the desired assertion status + * @see ClassLoader#setClassAssertionStatus(String, boolean) + * @see ClassLoader#setPackageAssertionStatus(String, boolean) + * @see ClassLoader#setDefaultAssertionStatus(boolean) + * @since 1.4 + */ + public boolean desiredAssertionStatus() + { + ClassLoader c = getClassLoaderInternal(); + Object status; + if (c == null) + return VMClassLoader.defaultAssertionStatus(); + if (c.classAssertionStatus != null) + synchronized (c) + { + status = c.classAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + status = ClassLoader.systemClassAssertionStatus.get(getName()); + if (status != null) + return status.equals(Boolean.TRUE); + } + if (c.packageAssertionStatus != null) + synchronized (c) + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = c.packageAssertionStatus.get(null); + else + do + { + status = c.packageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + else + { + String name = getPackagePortion(getName()); + if ("".equals(name)) + status = ClassLoader.systemPackageAssertionStatus.get(null); + else + do + { + status = ClassLoader.systemPackageAssertionStatus.get(name); + name = getPackagePortion(name); + } + while (! "".equals(name) && status == null); + if (status != null) + return status.equals(Boolean.TRUE); + } + return c.defaultAssertionStatus; + } + + /** + * Strip the last portion of the name (after the last dot). + * + * @param name the name to get package of + * @return the package name, or "" if no package + */ + private static String getPackagePortion(String name) + { + int lastInd = name.lastIndexOf('.'); + if (lastInd == -1) + return ""; + return name.substring(0, lastInd); + } + + /** + * Perform security checks common to all of the methods that + * get members of this Class. + */ + private void memberAccessCheck(int which) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + sm.checkMemberAccess(this, which); + Package pkg = getPackage(); + if (pkg != null) + sm.checkPackageAccess(pkg.getName()); + } + } + + /** + * Returns the simple name for this class, as used in the source + * code. For normal classes, this is the content returned by + * <code>getName()</code> which follows the last ".". Anonymous + * classes have no name, and so the result of calling this method is + * "". The simple name of an array consists of the simple name of + * its component type, followed by "[]". Thus, an array with the + * component type of an anonymous class has a simple name of simply + * "[]". + * + * @return the simple name for this class. + * @since 1.5 + */ + public String getSimpleName() + { + // FIXME write real implementation + return ""; + } + + /** + * Returns the class which immediately encloses this class. If this class + * is a top-level class, this method returns <code>null</code>. + * + * @return the immediate enclosing class, or <code>null</code> if this is + * a top-level class. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should return Class<?> */ + public Class getEnclosingClass() + { + // FIXME write real implementation + return null; + } + + /** + * Returns the constructor which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then <code>null</code> is returned. + * + * @return the immediate enclosing constructor if this class is + * declared within a constructor. Otherwise, <code>null</code> + * is returned. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should return Constructor<?> */ + public Constructor getEnclosingConstructor() + { + // FIXME write real implementation + return null; + } + + /** + * Returns the method which immediately encloses this class. If + * this class is a top-level class, or a local or anonymous class + * immediately enclosed by a type definition, instance initializer + * or static initializer, then <code>null</code> is returned. + * + * @return the immediate enclosing method if this class is + * declared within a method. Otherwise, <code>null</code> + * is returned. + * @since 1.5 + */ + public Method getEnclosingMethod() + { + // FIXME write real implementation + return null; + } + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this class, in declaration order. + * An array of size zero is returned if this class has no type + * variables. + * + * @return the type variables associated with this class. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should return TypeVariable<Class<T>> */ + public TypeVariable[] getTypeParameters() + { + // FIXME - provide real implementation. + return new TypeVariable[0]; + } + + /** + * Returns true if this class is an <code>Enum</code>. + * + * @return true if this is an enumeration class. + * @since 1.5 + */ + public boolean isEnum() + { + // FIXME - provide real implementation. + return false; + } + +} diff --git a/gcc-4.2.1/libjava/java/lang/ClassLoader.java b/gcc-4.2.1/libjava/java/lang/ClassLoader.java new file mode 100644 index 000000000..bcbfc298b --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/ClassLoader.java @@ -0,0 +1,998 @@ +/* ClassLoader.java -- responsible for loading classes into the VM + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.classpath.SystemProperties; +import gnu.java.util.DoubleEnumeration; +import gnu.java.util.EmptyEnumeration; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.Policy; +import java.security.ProtectionDomain; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * The ClassLoader is a way of customizing the way Java gets its classes + * and loads them into memory. The verifier and other standard Java things + * still run, but the ClassLoader is allowed great flexibility in determining + * where to get the classfiles and when to load and resolve them. For that + * matter, a custom ClassLoader can perform on-the-fly code generation or + * modification! + * + * <p>Every classloader has a parent classloader that is consulted before + * the 'child' classloader when classes or resources should be loaded. + * This is done to make sure that classes can be loaded from an hierarchy of + * multiple classloaders and classloaders do not accidentially redefine + * already loaded classes by classloaders higher in the hierarchy. + * + * <p>The grandparent of all classloaders is the bootstrap classloader, which + * loads all the standard system classes as implemented by GNU Classpath. The + * other special classloader is the system classloader (also called + * application classloader) that loads all classes from the CLASSPATH + * (<code>java.class.path</code> system property). The system classloader + * is responsible for finding the application classes from the classpath, + * and delegates all requests for the standard library classes to its parent + * the bootstrap classloader. Most programs will load all their classes + * through the system classloaders. + * + * <p>The bootstrap classloader in GNU Classpath is implemented as a couple of + * static (native) methods on the package private class + * <code>java.lang.VMClassLoader</code>, the system classloader is an + * instance of <code>gnu.java.lang.SystemClassLoader</code> + * (which is a subclass of <code>java.net.URLClassLoader</code>). + * + * <p>Users of a <code>ClassLoader</code> will normally just use the methods + * <ul> + * <li> <code>loadClass()</code> to load a class.</li> + * <li> <code>getResource()</code> or <code>getResourceAsStream()</code> + * to access a resource.</li> + * <li> <code>getResources()</code> to get an Enumeration of URLs to all + * the resources provided by the classloader and its parents with the + * same name.</li> + * </ul> + * + * <p>Subclasses should implement the methods + * <ul> + * <li> <code>findClass()</code> which is called by <code>loadClass()</code> + * when the parent classloader cannot provide a named class.</li> + * <li> <code>findResource()</code> which is called by + * <code>getResource()</code> when the parent classloader cannot provide + * a named resource.</li> + * <li> <code>findResources()</code> which is called by + * <code>getResource()</code> to combine all the resources with the + * same name from the classloader and its parents.</li> + * <li> <code>findLibrary()</code> which is called by + * <code>Runtime.loadLibrary()</code> when a class defined by the + * classloader wants to load a native library.</li> + * </ul> + * + * @author John Keiser + * @author Mark Wielaard + * @author Eric Blake (ebb9@email.byu.edu) + * @see Class + * @since 1.0 + * @status still missing 1.4 functionality + */ +public abstract class ClassLoader +{ + /** + * All classes loaded by this classloader. VM's may choose to implement + * this cache natively; but it is here available for use if necessary. It + * is not private in order to allow native code (and trusted subclasses) + * access to this field. + */ + final HashMap loadedClasses = new HashMap(); + + /** + * All packages defined by this classloader. It is not private in order to + * allow native code (and trusted subclasses) access to this field. + */ + final HashMap definedPackages = new HashMap(); + + /** + * The classloader that is consulted before this classloader. + * If null then the parent is the bootstrap classloader. + */ + private final ClassLoader parent; + + /** + * This is true if this classloader was successfully initialized. + * This flag is needed to avoid a class loader attack: even if the + * security manager rejects an attempt to create a class loader, the + * malicious class could have a finalize method which proceeds to + * define classes. + */ + private final boolean initialized; + + /** + * System/Application classloader: defaults to an instance of + * gnu.java.lang.SystemClassLoader, unless the first invocation of + * getSystemClassLoader loads another class loader because of the + * java.system.class.loader property. The initialization of this field + * is somewhat circular - getSystemClassLoader() checks whether this + * field is null in order to bypass a security check. + */ + static final ClassLoader systemClassLoader = + VMClassLoader.getSystemClassLoader(); + + static + { + // Find out if we have to install a default security manager. Note + // that this is done here because we potentially need the system + // class loader to load the security manager and note also that we + // don't need the security manager until the system class loader + // is created. If the runtime chooses to use a class loader that + // doesn't have the system class loader as its parent, it is + // responsible for setting up a security manager before doing so. + String secman = SystemProperties.getProperty("java.security.manager"); + if (secman != null && SecurityManager.current == null) + { + if (secman.equals("") || secman.equals("default")) + { + SecurityManager.current = new SecurityManager(); + } + else + { + try + { + Class cl = Class.forName(secman, false, systemClassLoader); + SecurityManager.current = (SecurityManager) cl.newInstance(); + } + catch (Exception x) + { + throw (InternalError) + new InternalError("Unable to create SecurityManager") + .initCause(x); + } + } + } + } + + /** + * The default protection domain, used when defining a class with a null + * paramter for the domain. + */ + static final ProtectionDomain defaultProtectionDomain; + static + { + CodeSource cs = new CodeSource(null, null); + PermissionCollection perm = Policy.getPolicy().getPermissions(cs); + defaultProtectionDomain = new ProtectionDomain(cs, perm); + } + + /** + * The desired assertion status of classes loaded by this loader, if not + * overridden by package or class instructions. + */ + // Package visible for use by Class. + boolean defaultAssertionStatus = VMClassLoader.defaultAssertionStatus(); + + /** + * The command-line state of the package assertion status overrides. This + * map is never modified, so it does not need to be synchronized. + */ + // Package visible for use by Class. + static final Map systemPackageAssertionStatus + = VMClassLoader.packageAssertionStatus(); + + /** + * The map of package assertion status overrides, or null if no package + * overrides have been specified yet. The values of the map should be + * Boolean.TRUE or Boolean.FALSE, and the unnamed package is represented + * by the null key. This map must be synchronized on this instance. + */ + // Package visible for use by Class. + Map packageAssertionStatus; + + /** + * The command-line state of the class assertion status overrides. This + * map is never modified, so it does not need to be synchronized. + */ + // Package visible for use by Class. + static final Map systemClassAssertionStatus + = VMClassLoader.classAssertionStatus(); + + /** + * The map of class assertion status overrides, or null if no class + * overrides have been specified yet. The values of the map should be + * Boolean.TRUE or Boolean.FALSE. This map must be synchronized on this + * instance. + */ + // Package visible for use by Class. + Map classAssertionStatus; + + /** + * Create a new ClassLoader with as parent the system classloader. There + * may be a security check for <code>checkCreateClassLoader</code>. + * + * @throws SecurityException if the security check fails + */ + protected ClassLoader() throws SecurityException + { + this(systemClassLoader); + } + + /** + * Create a new ClassLoader with the specified parent. The parent will + * be consulted when a class or resource is requested through + * <code>loadClass()</code> or <code>getResource()</code>. Only when the + * parent classloader cannot provide the requested class or resource the + * <code>findClass()</code> or <code>findResource()</code> method + * of this classloader will be called. There may be a security check for + * <code>checkCreateClassLoader</code>. + * + * @param parent the classloader's parent, or null for the bootstrap + * classloader + * @throws SecurityException if the security check fails + * @since 1.2 + */ + protected ClassLoader(ClassLoader parent) + { + // May we create a new classloader? + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkCreateClassLoader(); + this.parent = parent; + this.initialized = true; + } + + /** + * Load a class using this ClassLoader or its parent, without resolving + * it. Calls <code>loadClass(name, false)</code>. + * + * <p>Subclasses should not override this method but should override + * <code>findClass()</code> which is called by this method.</p> + * + * @param name the name of the class relative to this ClassLoader + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + public Class loadClass(String name) throws ClassNotFoundException + { + return loadClass(name, false); + } + + private native Class loadClassFromSig(String name) + throws ClassNotFoundException; + + /** + * Load a class using this ClassLoader or its parent, possibly resolving + * it as well using <code>resolveClass()</code>. It first tries to find + * out if the class has already been loaded through this classloader by + * calling <code>findLoadedClass()</code>. Then it calls + * <code>loadClass()</code> on the parent classloader (or when there is + * no parent it uses the VM bootclassloader). If the class is still + * not loaded it tries to create a new class by calling + * <code>findClass()</code>. Finally when <code>resolve</code> is + * <code>true</code> it also calls <code>resolveClass()</code> on the + * newly loaded class. + * + * <p>Subclasses should not override this method but should override + * <code>findClass()</code> which is called by this method.</p> + * + * @param name the fully qualified name of the class to load + * @param resolve whether or not to resolve the class + * @return the loaded class + * @throws ClassNotFoundException if the class cannot be found + */ + protected synchronized Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + // Arrays are handled specially. + Class c; + if (name.length() > 0 && name.charAt(0) == '[') + c = loadClassFromSig(name); + else + { + // Have we already loaded this class? + c = findLoadedClass(name); + if (c == null) + { + // Can the class be loaded by a parent? + try + { + if (parent == null) + { + c = VMClassLoader.loadClass(name, resolve); + if (c != null) + return c; + } + else + { + return parent.loadClass(name, resolve); + } + } + catch (ClassNotFoundException e) + { + } + // Still not found, we have to do it ourself. + c = findClass(name); + } + } + if (resolve) + resolveClass(c); + return c; + } + + /** + * Called for every class name that is needed but has not yet been + * defined by this classloader or one of its parents. It is called by + * <code>loadClass()</code> after both <code>findLoadedClass()</code> and + * <code>parent.loadClass()</code> couldn't provide the requested class. + * + * <p>The default implementation throws a + * <code>ClassNotFoundException</code>. Subclasses should override this + * method. An implementation of this method in a subclass should get the + * class bytes of the class (if it can find them), if the package of the + * requested class doesn't exist it should define the package and finally + * it should call define the actual class. It does not have to resolve the + * class. It should look something like the following:<br> + * + * <pre> + * // Get the bytes that describe the requested class + * byte[] classBytes = classLoaderSpecificWayToFindClassBytes(name); + * // Get the package name + * int lastDot = name.lastIndexOf('.'); + * if (lastDot != -1) + * { + * String packageName = name.substring(0, lastDot); + * // Look if the package already exists + * if (getPackage(packageName) == null) + * { + * // define the package + * definePackage(packageName, ...); + * } + * } + * // Define and return the class + * return defineClass(name, classBytes, 0, classBytes.length); + * </pre> + * + * <p><code>loadClass()</code> makes sure that the <code>Class</code> + * returned by <code>findClass()</code> will later be returned by + * <code>findLoadedClass()</code> when the same class name is requested. + * + * @param name class name to find (including the package name) + * @return the requested Class + * @throws ClassNotFoundException when the class can not be found + * @since 1.2 + */ + protected Class findClass(String name) throws ClassNotFoundException + { + throw new ClassNotFoundException(name); + } + + /** + * Helper to define a class using a string of bytes. This version is not + * secure. + * + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @deprecated use {@link #defineClass(String, byte[], int, int)} instead + */ + protected final Class defineClass(byte[] data, int offset, int len) + throws ClassFormatError + { + return defineClass(null, data, offset, len); + } + + /** + * Helper to define a class using a string of bytes without a + * ProtectionDomain. Subclasses should call this method from their + * <code>findClass()</code> implementation. The name should use '.' + * separators, and discard the trailing ".class". The default protection + * domain has the permissions of + * <code>Policy.getPolicy().getPermissions(new CodeSource(null, null))</code>. + * + * @param name the name to give the class, or null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @throws SecurityException if name starts with "java." + * @since 1.1 + */ + protected final Class defineClass(String name, byte[] data, int offset, + int len) throws ClassFormatError + { + return defineClass(name, data, offset, len, null); + } + + /** + * Helper to define a class using a string of bytes. Subclasses should call + * this method from their <code>findClass()</code> implementation. If the + * domain is null, the default of + * <code>Policy.getPolicy().getPermissions(new CodeSource(null, null))</code> + * is used. Once a class has been defined in a package, all further classes + * in that package must have the same set of certificates or a + * SecurityException is thrown. + * + * @param name the name to give the class. null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @param domain the ProtectionDomain to give to the class, null for the + * default protection domain + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + * @throws IndexOutOfBoundsException if offset or len is negative, or + * offset + len exceeds data + * @throws SecurityException if name starts with "java.", or if certificates + * do not match up + * @since 1.2 + */ + protected final synchronized Class defineClass(String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + throws ClassFormatError + { + if (domain == null) + domain = defaultProtectionDomain; + if (! initialized) + throw new SecurityException("attempt to define class from uninitialized class loader"); + + Class retval = VMClassLoader.defineClass(this, name, data, + offset, len, domain); + loadedClasses.put(retval.getName(), retval); + return retval; + } + + /** + * Links the class, if that has not already been done. Linking basically + * resolves all references to other classes made by this class. + * + * @param c the class to resolve + * @throws NullPointerException if c is null + * @throws LinkageError if linking fails + */ + protected final void resolveClass(Class c) + { + VMClassLoader.resolveClass(c); + } + + /** + * Helper to find a Class using the system classloader, possibly loading it. + * A subclass usually does not need to call this, if it correctly + * overrides <code>findClass(String)</code>. + * + * @param name the name of the class to find + * @return the found class + * @throws ClassNotFoundException if the class cannot be found + */ + protected final Class findSystemClass(String name) + throws ClassNotFoundException + { + return Class.forName(name, false, systemClassLoader); + } + + /** + * Returns the parent of this classloader. If the parent of this + * classloader is the bootstrap classloader then this method returns + * <code>null</code>. A security check may be performed on + * <code>RuntimePermission("getClassLoader")</code>. + * + * @return the parent <code>ClassLoader</code> + * @throws SecurityException if the security check fails + * @since 1.2 + */ + public final ClassLoader getParent() + { + // Check if we may return the parent classloader. + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + Class c = VMSecurityManager.getClassContext(ClassLoader.class)[0]; + ClassLoader cl = c.getClassLoader(); + if (cl != null && ! cl.isAncestorOf(this)) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + return parent; + } + + /** + * Helper to set the signers of a class. This should be called after + * defining the class. + * + * @param c the Class to set signers of + * @param signers the signers to set + * @since 1.1 + */ + protected final void setSigners(Class c, Object[] signers) + { + c.setSigners(signers); + } + + /** + * Helper to find an already-loaded class in this ClassLoader. + * + * @param name the name of the class to find + * @return the found Class, or null if it is not found + * @since 1.1 + */ + protected final synchronized Class findLoadedClass(String name) + { + // NOTE: If the VM is keeping its own cache, it may make sense to have + // this method be native. + return (Class) loadedClasses.get(name); + } + + /** + * Get the URL to a resource using this classloader or one of its parents. + * First tries to get the resource by calling <code>getResource()</code> + * on the parent classloader. If the parent classloader returns null then + * it tries finding the resource by calling <code>findResource()</code> on + * this classloader. The resource name should be separated by '/' for path + * elements. + * + * <p>Subclasses should not override this method but should override + * <code>findResource()</code> which is called by this method. + * + * @param name the name of the resource relative to this classloader + * @return the URL to the resource or null when not found + */ + public URL getResource(String name) + { + URL result; + + if (parent == null) + result = VMClassLoader.getResource(name); + else + result = parent.getResource(name); + + if (result == null) + result = findResource(name); + return result; + } + + /** + * Returns an Enumeration of all resources with a given name that can + * be found by this classloader and its parents. Certain classloaders + * (such as the URLClassLoader when given multiple jar files) can have + * multiple resources with the same name that come from multiple locations. + * It can also occur that a parent classloader offers a resource with a + * certain name and the child classloader also offers a resource with that + * same name. <code>getResource()</code> only offers the first resource (of the + * parent) with a given name. This method lists all resources with the + * same name. The name should use '/' as path separators. + * + * <p>The Enumeration is created by first calling <code>getResources()</code> + * on the parent classloader and then calling <code>findResources()</code> + * on this classloader.</p> + * + * @param name the resource name + * @return an enumaration of all resources found + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + public final Enumeration getResources(String name) throws IOException + { + Enumeration parentResources; + if (parent == null) + parentResources = VMClassLoader.getResources(name); + else + parentResources = parent.getResources(name); + return new DoubleEnumeration(parentResources, findResources(name)); + } + + /** + * Called whenever all locations of a named resource are needed. + * It is called by <code>getResources()</code> after it has called + * <code>parent.getResources()</code>. The results are combined by + * the <code>getResources()</code> method. + * + * <p>The default implementation always returns an empty Enumeration. + * Subclasses should override it when they can provide an Enumeration of + * URLs (possibly just one element) to the named resource. + * The first URL of the Enumeration should be the same as the one + * returned by <code>findResource</code>. + * + * @param name the name of the resource to be found + * @return a possibly empty Enumeration of URLs to the named resource + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + protected Enumeration findResources(String name) throws IOException + { + return EmptyEnumeration.getInstance(); + } + + /** + * Called whenever a resource is needed that could not be provided by + * one of the parents of this classloader. It is called by + * <code>getResource()</code> after <code>parent.getResource()</code> + * couldn't provide the requested resource. + * + * <p>The default implementation always returns null. Subclasses should + * override this method when they can provide a way to return a URL + * to a named resource. + * + * @param name the name of the resource to be found + * @return a URL to the named resource or null when not found + * @since 1.2 + */ + protected URL findResource(String name) + { + return null; + } + + /** + * Get the URL to a resource using the system classloader. + * + * @param name the name of the resource relative to the system classloader + * @return the URL to the resource + * @since 1.1 + */ + public static final URL getSystemResource(String name) + { + return systemClassLoader.getResource(name); + } + + /** + * Get an Enumeration of URLs to resources with a given name using the + * the system classloader. The enumeration firsts lists the resources with + * the given name that can be found by the bootstrap classloader followed + * by the resources with the given name that can be found on the classpath. + * + * @param name the name of the resource relative to the system classloader + * @return an Enumeration of URLs to the resources + * @throws IOException if I/O errors occur in the process + * @since 1.2 + */ + public static Enumeration getSystemResources(String name) throws IOException + { + return systemClassLoader.getResources(name); + } + + /** + * Get a resource as stream using this classloader or one of its parents. + * First calls <code>getResource()</code> and if that returns a URL to + * the resource then it calls and returns the InputStream given by + * <code>URL.openStream()</code>. + * + * <p>Subclasses should not override this method but should override + * <code>findResource()</code> which is called by this method. + * + * @param name the name of the resource relative to this classloader + * @return an InputStream to the resource, or null + * @since 1.1 + */ + public InputStream getResourceAsStream(String name) + { + try + { + URL url = getResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + + /** + * Get a resource using the system classloader. + * + * @param name the name of the resource relative to the system classloader + * @return an input stream for the resource, or null + * @since 1.1 + */ + public static final InputStream getSystemResourceAsStream(String name) + { + try + { + URL url = getSystemResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + + /** + * Returns the system classloader. The system classloader (also called + * the application classloader) is the classloader that was used to + * load the application classes on the classpath (given by the system + * property <code>java.class.path</code>. This is set as the context + * class loader for a thread. The system property + * <code>java.system.class.loader</code>, if defined, is taken to be the + * name of the class to use as the system class loader, which must have + * a public constructor which takes a ClassLoader as a parent; otherwise this + * uses gnu.java.lang.SystemClassLoader. + * + * <p>Note that this is different from the bootstrap classloader that + * actually loads all the real "system" classes (the bootstrap classloader + * is the parent of the returned system classloader). + * + * <p>A security check will be performed for + * <code>RuntimePermission("getClassLoader")</code> if the calling class + * is not a parent of the system class loader. + * + * @return the system class loader + * @throws SecurityException if the security check fails + * @throws IllegalStateException if this is called recursively + * @throws Error if <code>java.system.class.loader</code> fails to load + * @since 1.2 + */ + public static ClassLoader getSystemClassLoader() + { + // Check if we may return the system classloader + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + Class c = VMSecurityManager.getClassContext(ClassLoader.class)[0]; + ClassLoader cl = c.getClassLoader(); + if (cl != null && cl != systemClassLoader) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + + return systemClassLoader; + } + + /** + * Defines a new package and creates a Package object. The package should + * be defined before any class in the package is defined with + * <code>defineClass()</code>. The package should not yet be defined + * before in this classloader or in one of its parents (which means that + * <code>getPackage()</code> should return <code>null</code>). All + * parameters except the <code>name</code> of the package may be + * <code>null</code>. + * + * <p>Subclasses should call this method from their <code>findClass()</code> + * implementation before calling <code>defineClass()</code> on a Class + * in a not yet defined Package (which can be checked by calling + * <code>getPackage()</code>). + * + * @param name the name of the Package + * @param specTitle the name of the specification + * @param specVendor the name of the specification designer + * @param specVersion the version of this specification + * @param implTitle the name of the implementation + * @param implVendor the vendor that wrote this implementation + * @param implVersion the version of this implementation + * @param sealed if sealed the origin of the package classes + * @return the Package object for the specified package + * @throws IllegalArgumentException if the package name is null or it + * was already defined by this classloader or one of its parents + * @see Package + * @since 1.2 + */ + protected Package definePackage(String name, String specTitle, + String specVendor, String specVersion, + String implTitle, String implVendor, + String implVersion, URL sealed) + { + if (getPackage(name) != null) + throw new IllegalArgumentException("Package " + name + + " already defined"); + Package p = new Package(name, specTitle, specVendor, specVersion, + implTitle, implVendor, implVersion, sealed); + synchronized (definedPackages) + { + definedPackages.put(name, p); + } + return p; + } + + /** + * Returns the Package object for the requested package name. It returns + * null when the package is not defined by this classloader or one of its + * parents. + * + * @param name the package name to find + * @return the package, if defined + * @since 1.2 + */ + protected Package getPackage(String name) + { + Package p; + if (parent == null) + p = VMClassLoader.getPackage(name); + else + p = parent.getPackage(name); + + if (p == null) + { + synchronized (definedPackages) + { + p = (Package) definedPackages.get(name); + } + } + return p; + } + + /** + * Returns all Package objects defined by this classloader and its parents. + * + * @return an array of all defined packages + * @since 1.2 + */ + protected Package[] getPackages() + { + // Get all our packages. + Package[] packages; + synchronized(definedPackages) + { + packages = new Package[definedPackages.size()]; + definedPackages.values().toArray(packages); + } + + // If we have a parent get all packages defined by our parents. + Package[] parentPackages; + if (parent == null) + parentPackages = VMClassLoader.getPackages(); + else + parentPackages = parent.getPackages(); + + Package[] allPackages = new Package[parentPackages.length + + packages.length]; + System.arraycopy(parentPackages, 0, allPackages, 0, + parentPackages.length); + System.arraycopy(packages, 0, allPackages, parentPackages.length, + packages.length); + return allPackages; + } + + /** + * Called by <code>Runtime.loadLibrary()</code> to get an absolute path + * to a (system specific) library that was requested by a class loaded + * by this classloader. The default implementation returns + * <code>null</code>. It should be implemented by subclasses when they + * have a way to find the absolute path to a library. If this method + * returns null the library is searched for in the default locations + * (the directories listed in the <code>java.library.path</code> system + * property). + * + * @param name the (system specific) name of the requested library + * @return the full pathname to the requested library, or null + * @see Runtime#loadLibrary() + * @since 1.2 + */ + protected String findLibrary(String name) + { + return null; + } + + /** + * Set the default assertion status for classes loaded by this classloader, + * used unless overridden by a package or class request. + * + * @param enabled true to set the default to enabled + * @see #setClassAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public void setDefaultAssertionStatus(boolean enabled) + { + defaultAssertionStatus = enabled; + } + + /** + * Set the default assertion status for packages, used unless overridden + * by a class request. This default also covers subpackages, unless they + * are also specified. The unnamed package should use null for the name. + * + * @param name the package (and subpackages) to affect + * @param enabled true to set the default to enabled + * @see #setDefaultAssertionStatus(String, boolean) + * @see #setClassAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public synchronized void setPackageAssertionStatus(String name, + boolean enabled) + { + if (packageAssertionStatus == null) + packageAssertionStatus + = new HashMap(systemPackageAssertionStatus); + packageAssertionStatus.put(name, Boolean.valueOf(enabled)); + } + + /** + * Set the default assertion status for a class. This only affects the + * status of top-level classes, any other string is harmless. + * + * @param name the class to affect + * @param enabled true to set the default to enabled + * @throws NullPointerException if name is null + * @see #setDefaultAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @see #clearAssertionStatus() + * @since 1.4 + */ + public synchronized void setClassAssertionStatus(String name, + boolean enabled) + { + if (classAssertionStatus == null) + classAssertionStatus = new HashMap(systemClassAssertionStatus); + // The toString() hack catches null, as required. + classAssertionStatus.put(name.toString(), Boolean.valueOf(enabled)); + } + + /** + * Resets the default assertion status of this classloader, its packages + * and classes, all to false. This allows overriding defaults inherited + * from the command line. + * + * @see #setDefaultAssertionStatus(boolean) + * @see #setClassAssertionStatus(String, boolean) + * @see #setPackageAssertionStatus(String, boolean) + * @since 1.4 + */ + public synchronized void clearAssertionStatus() + { + defaultAssertionStatus = false; + packageAssertionStatus = new HashMap(); + classAssertionStatus = new HashMap(); + } + + /** + * Return true if this loader is either the specified class loader + * or an ancestor thereof. + * @param loader the class loader to check + */ + final boolean isAncestorOf(ClassLoader loader) + { + while (loader != null) + { + if (this == loader) + return true; + loader = loader.parent; + } + return false; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/EcosProcess.java b/gcc-4.2.1/libjava/java/lang/EcosProcess.java new file mode 100644 index 000000000..aff534a39 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/EcosProcess.java @@ -0,0 +1,63 @@ +// EcosProcess.java - Subclass of Process for eCos systems. + +/* Copyright (C) 1998, 1999 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * @author Tom Tromey <tromey@cygnus.com> + * @date May 11, 1999 + */ + +// This is entirely internal to our implementation. + +// This file is copied to `ConcreteProcess.java' before compilation. +// Hence the class name apparently does not match the file name. +final class ConcreteProcess extends Process +{ + // See natEcosProcess.cc to understand why this is native. + public native void destroy (); + + public int exitValue () + { + return 0; + } + public InputStream getErrorStream () + { + return null; + } + + public InputStream getInputStream () + { + return null; + } + + public OutputStream getOutputStream () + { + return null; + } + + public int waitFor () throws InterruptedException + { + return 0; + } + + public ConcreteProcess (String[] progarray, + String[] envp, + File dir) + throws IOException + { + throw new IOException ("eCos processes unimplemented"); + } +} diff --git a/gcc-4.2.1/libjava/java/lang/Math.java b/gcc-4.2.1/libjava/java/lang/Math.java new file mode 100644 index 000000000..836b8bd86 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Math.java @@ -0,0 +1,973 @@ +/* java.lang.Math -- common mathematical functions, native allowed + Copyright (C) 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.classpath.Configuration; + +import java.util.Random; + +/** + * Helper class containing useful mathematical functions and constants. + * <P> + * + * Note that angles are specified in radians. Conversion functions are + * provided for your convenience. + * + * @author Paul Fisher + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + */ +public final class Math +{ + /** + * Math is non-instantiable + */ + private Math() + { + } + + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalang"); + } + } + + /** + * A random number generator, initialized on first use. + */ + private static Random rand; + + /** + * The most accurate approximation to the mathematical constant <em>e</em>: + * <code>2.718281828459045</code>. Used in natural log and exp. + * + * @see #log(double) + * @see #exp(double) + */ + public static final double E = 2.718281828459045; + + /** + * The most accurate approximation to the mathematical constant <em>pi</em>: + * <code>3.141592653589793</code>. This is the ratio of a circle's diameter + * to its circumference. + */ + public static final double PI = 3.141592653589793; + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * <P> + * + * Note that the the largest negative value (Integer.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a <em>negative</em> value. You have been warned. + * + * @param i the number to take the absolute value of + * @return the absolute value + * @see Integer#MIN_VALUE + */ + public static int abs(int i) + { + return (i < 0) ? -i : i; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * <P> + * + * Note that the the largest negative value (Long.MIN_VALUE) cannot + * be made positive. In this case, because of the rules of negation in + * a computer, MIN_VALUE is what will be returned. + * This is a <em>negative</em> value. You have been warned. + * + * @param l the number to take the absolute value of + * @return the absolute value + * @see Long#MIN_VALUE + */ + public static long abs(long l) + { + return (l < 0) ? -l : l; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * <P> + * + * This is equivalent, but faster than, calling + * <code>Float.intBitsToFloat(0x7fffffff & Float.floatToIntBits(a))</code>. + * + * @param f the number to take the absolute value of + * @return the absolute value + */ + public static float abs(float f) + { + return (f <= 0) ? 0 - f : f; + } + + /** + * Take the absolute value of the argument. + * (Absolute value means make it positive.) + * + * This is equivalent, but faster than, calling + * <code>Double.longBitsToDouble(Double.doubleToLongBits(a) + * << 1) >>> 1);</code>. + * + * @param d the number to take the absolute value of + * @return the absolute value + */ + public static double abs(double d) + { + return (d <= 0) ? 0 - d : d; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static int min(int a, int b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static long min(long a, long b) + { + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static float min(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is smaller. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, -0 is always smaller. + * + * @param a the first number + * @param b a second number + * @return the smaller of the two numbers + */ + public static double min(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; < will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return -(-a - b); + return (a < b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static int max(int a, int b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static long max(long a, long b) + { + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static float max(float a, float b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * Return whichever argument is larger. If either argument is NaN, the + * result is NaN, and when comparing 0 and -0, 0 is always larger. + * + * @param a the first number + * @param b a second number + * @return the larger of the two numbers + */ + public static double max(double a, double b) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return a; + // no need to check if b is NaN; > will work correctly + // recall that -0.0 == 0.0, but [+-]0.0 - [+-]0.0 behaves special + if (a == 0 && b == 0) + return a - -b; + return (a > b) ? a : b; + } + + /** + * The trigonometric function <em>sin</em>. The sine of NaN or infinity is + * NaN, and the sine of 0 retains its sign. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the angle (in radians) + * @return sin(a) + */ + public static native double sin(double a); + + /** + * The trigonometric function <em>cos</em>. The cosine of NaN or infinity is + * NaN. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return cos(a) + */ + public static native double cos(double a); + + /** + * The trigonometric function <em>tan</em>. The tangent of NaN or infinity + * is NaN, and the tangent of 0 retains its sign. This is accurate within 1 + * ulp, and is semi-monotonic. + * + * @param a the angle (in radians) + * @return tan(a) + */ + public static native double tan(double a); + + /** + * The trigonometric function <em>arcsin</em>. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN; and the arcsine of + * 0 retains its sign. This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the sin to turn back into an angle + * @return arcsin(a) + */ + public static native double asin(double a); + + /** + * The trigonometric function <em>arccos</em>. The range of angles returned + * is 0 to pi radians (0 to 180 degrees). If the argument is NaN or + * its absolute value is beyond 1, the result is NaN. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the cos to turn back into an angle + * @return arccos(a) + */ + public static native double acos(double a); + + /** + * The trigonometric function <em>arcsin</em>. The range of angles returned + * is -pi/2 to pi/2 radians (-90 to 90 degrees). If the argument is NaN, the + * result is NaN; and the arctangent of 0 retains its sign. This is accurate + * within 1 ulp, and is semi-monotonic. + * + * @param a the tan to turn back into an angle + * @return arcsin(a) + * @see #atan2(double, double) + */ + public static native double atan(double a); + + /** + * A special version of the trigonometric function <em>arctan</em>, for + * converting rectangular coordinates <em>(x, y)</em> to polar + * <em>(r, theta)</em>. This computes the arctangent of x/y in the range + * of -pi to pi radians (-180 to 180 degrees). Special cases:<ul> + * <li>If either argument is NaN, the result is NaN.</li> + * <li>If the first argument is positive zero and the second argument is + * positive, or the first argument is positive and finite and the second + * argument is positive infinity, then the result is positive zero.</li> + * <li>If the first argument is negative zero and the second argument is + * positive, or the first argument is negative and finite and the second + * argument is positive infinity, then the result is negative zero.</li> + * <li>If the first argument is positive zero and the second argument is + * negative, or the first argument is positive and finite and the second + * argument is negative infinity, then the result is the double value + * closest to pi.</li> + * <li>If the first argument is negative zero and the second argument is + * negative, or the first argument is negative and finite and the second + * argument is negative infinity, then the result is the double value + * closest to -pi.</li> + * <li>If the first argument is positive and the second argument is + * positive zero or negative zero, or the first argument is positive + * infinity and the second argument is finite, then the result is the + * double value closest to pi/2.</li> + * <li>If the first argument is negative and the second argument is + * positive zero or negative zero, or the first argument is negative + * infinity and the second argument is finite, then the result is the + * double value closest to -pi/2.</li> + * <li>If both arguments are positive infinity, then the result is the + * double value closest to pi/4.</li> + * <li>If the first argument is positive infinity and the second argument + * is negative infinity, then the result is the double value closest to + * 3*pi/4.</li> + * <li>If the first argument is negative infinity and the second argument + * is positive infinity, then the result is the double value closest to + * -pi/4.</li> + * <li>If both arguments are negative infinity, then the result is the + * double value closest to -3*pi/4.</li> + * + * </ul><p>This is accurate within 2 ulps, and is semi-monotonic. To get r, + * use sqrt(x*x+y*y). + * + * @param y the y position + * @param x the x position + * @return <em>theta</em> in the conversion of (x, y) to (r, theta) + * @see #atan(double) + */ + public static native double atan2(double y, double x); + + /** + * Take <em>e</em><sup>a</sup>. The opposite of <code>log()</code>. If the + * argument is NaN, the result is NaN; if the argument is positive infinity, + * the result is positive infinity; and if the argument is negative + * infinity, the result is positive zero. This is accurate within 1 ulp, + * and is semi-monotonic. + * + * @param a the number to raise to the power + * @return the number raised to the power of <em>e</em> + * @see #log(double) + * @see #pow(double, double) + */ + public static native double exp(double a); + + /** + * Take ln(a) (the natural log). The opposite of <code>exp()</code>. If the + * argument is NaN or negative, the result is NaN; if the argument is + * positive infinity, the result is positive infinity; and if the argument + * is either zero, the result is negative infinity. This is accurate within + * 1 ulp, and is semi-monotonic. + * + * <p>Note that the way to get log<sub>b</sub>(a) is to do this: + * <code>ln(a) / ln(b)</code>. + * + * @param a the number to take the natural log of + * @return the natural log of <code>a</code> + * @see #exp(double) + */ + public static native double log(double a); + + /** + * Take a square root. If the argument is NaN or negative, the result is + * NaN; if the argument is positive infinity, the result is positive + * infinity; and if the result is either zero, the result is the same. + * This is accurate within the limits of doubles. + * + * <p>For other roots, use pow(a, 1 / rootNumber). + * + * @param a the numeric argument + * @return the square root of the argument + * @see #pow(double, double) + */ + public static native double sqrt(double a); + + /** + * Raise a number to a power. Special cases:<ul> + * <li>If the second argument is positive or negative zero, then the result + * is 1.0.</li> + * <li>If the second argument is 1.0, then the result is the same as the + * first argument.</li> + * <li>If the second argument is NaN, then the result is NaN.</li> + * <li>If the first argument is NaN and the second argument is nonzero, + * then the result is NaN.</li> + * <li>If the absolute value of the first argument is greater than 1 and + * the second argument is positive infinity, or the absolute value of the + * first argument is less than 1 and the second argument is negative + * infinity, then the result is positive infinity.</li> + * <li>If the absolute value of the first argument is greater than 1 and + * the second argument is negative infinity, or the absolute value of the + * first argument is less than 1 and the second argument is positive + * infinity, then the result is positive zero.</li> + * <li>If the absolute value of the first argument equals 1 and the second + * argument is infinite, then the result is NaN.</li> + * <li>If the first argument is positive zero and the second argument is + * greater than zero, or the first argument is positive infinity and the + * second argument is less than zero, then the result is positive zero.</li> + * <li>If the first argument is positive zero and the second argument is + * less than zero, or the first argument is positive infinity and the + * second argument is greater than zero, then the result is positive + * infinity.</li> + * <li>If the first argument is negative zero and the second argument is + * greater than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is less than zero but not a + * finite odd integer, then the result is positive zero.</li> + * <li>If the first argument is negative zero and the second argument is a + * positive finite odd integer, or the first argument is negative infinity + * and the second argument is a negative finite odd integer, then the result + * is negative zero.</li> + * <li>If the first argument is negative zero and the second argument is + * less than zero but not a finite odd integer, or the first argument is + * negative infinity and the second argument is greater than zero but not a + * finite odd integer, then the result is positive infinity.</li> + * <li>If the first argument is negative zero and the second argument is a + * negative finite odd integer, or the first argument is negative infinity + * and the second argument is a positive finite odd integer, then the result + * is negative infinity.</li> + * <li>If the first argument is less than zero and the second argument is a + * finite even integer, then the result is equal to the result of raising + * the absolute value of the first argument to the power of the second + * argument.</li> + * <li>If the first argument is less than zero and the second argument is a + * finite odd integer, then the result is equal to the negative of the + * result of raising the absolute value of the first argument to the power + * of the second argument.</li> + * <li>If the first argument is finite and less than zero and the second + * argument is finite and not an integer, then the result is NaN.</li> + * <li>If both arguments are integers, then the result is exactly equal to + * the mathematical result of raising the first argument to the power of + * the second argument if that result can in fact be represented exactly as + * a double value.</li> + * + * </ul><p>(In the foregoing descriptions, a floating-point value is + * considered to be an integer if and only if it is a fixed point of the + * method {@link #ceil(double)} or, equivalently, a fixed point of the + * method {@link #floor(double)}. A value is a fixed point of a one-argument + * method if and only if the result of applying the method to the value is + * equal to the value.) This is accurate within 1 ulp, and is semi-monotonic. + * + * @param a the number to raise + * @param b the power to raise it to + * @return a<sup>b</sup> + */ + public static native double pow(double a, double b); + + /** + * Get the IEEE 754 floating point remainder on two numbers. This is the + * value of <code>x - y * <em>n</em></code>, where <em>n</em> is the closest + * double to <code>x / y</code> (ties go to the even n); for a zero + * remainder, the sign is that of <code>x</code>. If either argument is NaN, + * the first argument is infinite, or the second argument is zero, the result + * is NaN; if x is finite but y is infinite, the result is x. This is + * accurate within the limits of doubles. + * + * @param x the dividend (the top half) + * @param y the divisor (the bottom half) + * @return the IEEE 754-defined floating point remainder of x/y + * @see #rint(double) + */ + public static native double IEEEremainder(double x, double y); + + /** + * Take the nearest integer that is that is greater than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same; if the argument is between -1 and 0, the result is negative zero. + * Note that <code>Math.ceil(x) == -Math.floor(-x)</code>. + * + * @param a the value to act upon + * @return the nearest integer >= <code>a</code> + */ + public static native double ceil(double a); + + /** + * Take the nearest integer that is that is less than or equal to the + * argument. If the argument is NaN, infinite, or zero, the result is the + * same. Note that <code>Math.ceil(x) == -Math.floor(-x)</code>. + * + * @param a the value to act upon + * @return the nearest integer <= <code>a</code> + */ + public static native double floor(double a); + + /** + * Take the nearest integer to the argument. If it is exactly between + * two integers, the even integer is taken. If the argument is NaN, + * infinite, or zero, the result is the same. + * + * @param a the value to act upon + * @return the nearest integer to <code>a</code> + */ + public static native double rint(double a); + + /** + * Take the nearest integer to the argument. This is equivalent to + * <code>(int) Math.floor(a + 0.5f)</code>. If the argument is NaN, the result + * is 0; otherwise if the argument is outside the range of int, the result + * will be Integer.MIN_VALUE or Integer.MAX_VALUE, as appropriate. + * + * @param a the argument to round + * @return the nearest integer to the argument + * @see Integer#MIN_VALUE + * @see Integer#MAX_VALUE + */ + public static int round(float a) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return 0; + return (int) floor(a + 0.5f); + } + + /** + * Take the nearest long to the argument. This is equivalent to + * <code>(long) Math.floor(a + 0.5)</code>. If the argument is NaN, the + * result is 0; otherwise if the argument is outside the range of long, the + * result will be Long.MIN_VALUE or Long.MAX_VALUE, as appropriate. + * + * @param a the argument to round + * @return the nearest long to the argument + * @see Long#MIN_VALUE + * @see Long#MAX_VALUE + */ + public static long round(double a) + { + // this check for NaN, from JLS 15.21.1, saves a method call + if (a != a) + return 0; + return (long) floor(a + 0.5d); + } + + /** + * Get a random number. This behaves like Random.nextDouble(), seeded by + * System.currentTimeMillis() when first called. In other words, the number + * is from a pseudorandom sequence, and lies in the range [+0.0, 1.0). + * This random sequence is only used by this method, and is threadsafe, + * although you may want your own random number generator if it is shared + * among threads. + * + * @return a random number + * @see Random#nextDouble() + * @see System#currentTimeMillis() + */ + public static synchronized double random() + { + if (rand == null) + rand = new Random(); + return rand.nextDouble(); + } + + /** + * Convert from degrees to radians. The formula for this is + * radians = degrees * (pi/180); however it is not always exact given the + * limitations of floating point numbers. + * + * @param degrees an angle in degrees + * @return the angle in radians + * @since 1.2 + */ + public static double toRadians(double degrees) + { + return (degrees * PI) / 180; + } + + /** + * Convert from radians to degrees. The formula for this is + * degrees = radians * (180/pi); however it is not always exact given the + * limitations of floating point numbers. + * + * @param rads an angle in radians + * @return the angle in degrees + * @since 1.2 + */ + public static double toDegrees(double rads) + { + return (rads * 180) / PI; + } + + /** + * <p> + * Take a cube root. If the argument is <code>NaN</code>, an infinity or + * zero, then the original value is returned. The returned result is + * within 1 ulp of the exact result. For a finite value, <code>x</code>, + * the cube root of <code>-x</code> is equal to the negation of the cube root + * of <code>x</code>. + * </p> + * <p> + * For a square root, use <code>sqrt</code>. For other roots, use + * <code>pow(a, 1 / rootNumber)</code>. + * </p> + * + * @param a the numeric argument + * @return the cube root of the argument + * @see #sqrt(double) + * @see #pow(double, double) + * @since 1.5 + */ + public static native double cbrt(double a); + + /** + * <p> + * Returns the hyperbolic cosine of the given value. For a value, + * <code>x</code>, the hyperbolic cosine is <code>(e<sup>x</sup> + + * e<sup>-x</sup>)/2</code> + * with <code>e</code> being <a href="#E">Euler's number</a>. The returned + * result is within 2.5 ulps of the exact result. + * </p> + * <p> + * If the supplied value is <code>NaN</code>, then the original value is + * returned. For either infinity, positive infinity is returned. + * The hyperbolic cosine of zero is 1.0. + * </p> + * + * @param a the numeric argument + * @return the hyperbolic cosine of <code>a</code>. + * @since 1.5 + */ + public static native double cosh(double a); + + /** + * <p> + * Returns <code>e<sup>a</sup> - 1. For values close to 0, the + * result of <code>expm1(a) + 1</code> tend to be much closer to the + * exact result than simply <code>exp(x)</code>. The result is within + * 1 ulp of the exact result, and results are semi-monotonic. For finite + * inputs, the returned value is greater than or equal to -1.0. Once + * a result enters within half a ulp of this limit, the limit is returned. + * </p> + * <p> + * For <code>NaN</code>, positive infinity and zero, the original value + * is returned. Negative infinity returns a result of -1.0 (the limit). + * </p> + * + * @param a the numeric argument + * @return <code>e<sup>a</sup> - 1</code> + * @since 1.5 + */ + public static native double expm1(double a); + + /** + * <p> + * Returns the hypotenuse, <code>a<sup>2</sup> + b<sup>2</sup></code>, + * without intermediate overflow or underflow. The returned result is + * within 1 ulp of the exact result. If one parameter is held constant, + * then the result in the other parameter is semi-monotonic. + * </p> + * <p> + * If either of the arguments is an infinity, then the returned result + * is positive infinity. Otherwise, if either argument is <code>NaN</code>, + * then <code>NaN</code> is returned. + * </p> + * + * @param a the first parameter. + * @param b the second parameter. + * @return the hypotenuse matching the supplied parameters. + * @since 1.5 + */ + public static native double hypot(double a, double b); + + /** + * <p> + * Returns the base 10 logarithm of the supplied value. The returned + * result is within 1 ulp of the exact result, and the results are + * semi-monotonic. + * </p> + * <p> + * Arguments of either <code>NaN</code> or less than zero return + * <code>NaN</code>. An argument of positive infinity returns positive + * infinity. Negative infinity is returned if either positive or negative + * zero is supplied. Where the argument is the result of + * <code>10<sup>n</sup</code>, then <code>n</code> is returned. + * </p> + * + * @param a the numeric argument. + * @return the base 10 logarithm of <code>a</code>. + * @since 1.5 + */ + public static native double log10(double a); + + /** + * <p> + * Returns the natural logarithm resulting from the sum of the argument, + * <code>a</code> and 1. For values close to 0, the + * result of <code>log1p(a)</code> tend to be much closer to the + * exact result than simply <code>log(1.0+a)</code>. The returned + * result is within 1 ulp of the exact result, and the results are + * semi-monotonic. + * </p> + * <p> + * Arguments of either <code>NaN</code> or less than -1 return + * <code>NaN</code>. An argument of positive infinity or zero + * returns the original argument. Negative infinity is returned from an + * argument of -1. + * </p> + * + * @param a the numeric argument. + * @return the natural logarithm of <code>a</code> + 1. + * @since 1.5 + */ + public static native double log1p(double a); + + /** + * <p> + * Returns the sign of the argument as follows: + * </p> + * <ul> + * <li>If <code>a</code> is greater than zero, the result is 1.0.</li> + * <li>If <code>a</code> is less than zero, the result is -1.0.</li> + * <li>If <code>a</code> is <code>NaN</code>, the result is <code>NaN</code>. + * <li>If <code>a</code> is positive or negative zero, the result is the + * same.</li> + * </ul> + * + * @param a the numeric argument. + * @return the sign of the argument. + * @since 1.5. + */ + public static double signum(double a) + { + if (Double.isNaN(a)) + return Double.NaN; + if (a > 0) + return 1.0; + if (a < 0) + return -1.0; + return a; + } + + /** + * <p> + * Returns the sign of the argument as follows: + * </p> + * <ul> + * <li>If <code>a</code> is greater than zero, the result is 1.0f.</li> + * <li>If <code>a</code> is less than zero, the result is -1.0f.</li> + * <li>If <code>a</code> is <code>NaN</code>, the result is <code>NaN</code>. + * <li>If <code>a</code> is positive or negative zero, the result is the + * same.</li> + * </ul> + * + * @param a the numeric argument. + * @return the sign of the argument. + * @since 1.5. + */ + public static float signum(float a) + { + if (Float.isNaN(a)) + return Float.NaN; + if (a > 0) + return 1.0f; + if (a < 0) + return -1.0f; + return a; + } + + /** + * <p> + * Returns the hyperbolic sine of the given value. For a value, + * <code>x</code>, the hyperbolic sine is <code>(e<sup>x</sup> - + * e<sup>-x</sup>)/2</code> + * with <code>e</code> being <a href="#E">Euler's number</a>. The returned + * result is within 2.5 ulps of the exact result. + * </p> + * <p> + * If the supplied value is <code>NaN</code>, an infinity or a zero, then the + * original value is returned. + * </p> + * + * @param a the numeric argument + * @return the hyperbolic sine of <code>a</code>. + * @since 1.5 + */ + public static native double sinh(double a); + + /** + * <p> + * Returns the hyperbolic tangent of the given value. For a value, + * <code>x</code>, the hyperbolic tangent is <code>(e<sup>x</sup> - + * e<sup>-x</sup>)/(e<sup>x</sup> + e<sup>-x</sup>)</code> + * (i.e. <code>sinh(a)/cosh(a)</code>) + * with <code>e</code> being <a href="#E">Euler's number</a>. The returned + * result is within 2.5 ulps of the exact result. The absolute value + * of the exact result is always less than 1. Computed results are thus + * less than or equal to 1 for finite arguments, with results within + * half a ulp of either positive or negative 1 returning the appropriate + * limit value (i.e. as if the argument was an infinity). + * </p> + * <p> + * If the supplied value is <code>NaN</code> or zero, then the original + * value is returned. Positive infinity returns +1.0 and negative infinity + * returns -1.0. + * </p> + * + * @param a the numeric argument + * @return the hyperbolic tangent of <code>a</code>. + * @since 1.5 + */ + public static native double tanh(double a); + + /** + * Return the ulp for the given double argument. The ulp is the + * difference between the argument and the next larger double. Note + * that the sign of the double argument is ignored, that is, + * ulp(x) == ulp(-x). If the argument is a NaN, then NaN is returned. + * If the argument is an infinity, then +Inf is returned. If the + * argument is zero (either positive or negative), then + * {@link Double#MIN_VALUE} is returned. + * @param d the double whose ulp should be returned + * @return the difference between the argument and the next larger double + * @since 1.5 + */ + public static double ulp(double d) + { + if (Double.isNaN(d)) + return d; + if (Double.isInfinite(d)) + return Double.POSITIVE_INFINITY; + // This handles both +0.0 and -0.0. + if (d == 0.0) + return Double.MIN_VALUE; + long bits = Double.doubleToLongBits(d); + final int mantissaBits = 52; + final int exponentBits = 11; + final long mantMask = (1L << mantissaBits) - 1; + long mantissa = bits & mantMask; + final long expMask = (1L << exponentBits) - 1; + long exponent = (bits >>> mantissaBits) & expMask; + + // Denormal number, so the answer is easy. + if (exponent == 0) + { + long result = (exponent << mantissaBits) | 1L; + return Double.longBitsToDouble(result); + } + + // Conceptually we want to have '1' as the mantissa. Then we would + // shift the mantissa over to make a normal number. If this underflows + // the exponent, we will make a denormal result. + long newExponent = exponent - mantissaBits; + long newMantissa; + if (newExponent > 0) + newMantissa = 0; + else + { + newMantissa = 1L << -(newExponent - 1); + newExponent = 0; + } + return Double.longBitsToDouble((newExponent << mantissaBits) | newMantissa); + } + + /** + * Return the ulp for the given float argument. The ulp is the + * difference between the argument and the next larger float. Note + * that the sign of the float argument is ignored, that is, + * ulp(x) == ulp(-x). If the argument is a NaN, then NaN is returned. + * If the argument is an infinity, then +Inf is returned. If the + * argument is zero (either positive or negative), then + * {@link Float#MIN_VALUE} is returned. + * @param f the float whose ulp should be returned + * @return the difference between the argument and the next larger float + * @since 1.5 + */ + public static float ulp(float f) + { + if (Float.isNaN(f)) + return f; + if (Float.isInfinite(f)) + return Float.POSITIVE_INFINITY; + // This handles both +0.0 and -0.0. + if (f == 0.0) + return Float.MIN_VALUE; + int bits = Float.floatToIntBits(f); + final int mantissaBits = 23; + final int exponentBits = 8; + final int mantMask = (1 << mantissaBits) - 1; + int mantissa = bits & mantMask; + final int expMask = (1 << exponentBits) - 1; + int exponent = (bits >>> mantissaBits) & expMask; + + // Denormal number, so the answer is easy. + if (exponent == 0) + { + int result = (exponent << mantissaBits) | 1; + return Float.intBitsToFloat(result); + } + + // Conceptually we want to have '1' as the mantissa. Then we would + // shift the mantissa over to make a normal number. If this underflows + // the exponent, we will make a denormal result. + int newExponent = exponent - mantissaBits; + int newMantissa; + if (newExponent > 0) + newMantissa = 0; + else + { + newMantissa = 1 << -(newExponent - 1); + newExponent = 0; + } + return Float.intBitsToFloat((newExponent << mantissaBits) | newMantissa); + } +} diff --git a/gcc-4.2.1/libjava/java/lang/Object.h b/gcc-4.2.1/libjava/java/lang/Object.h new file mode 100644 index 000000000..54fd447d1 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Object.h @@ -0,0 +1,91 @@ +// Object.h - Header file for java.lang.Object. -*- c++ -*- + +/* Copyright (C) 1998, 1999, 2000, 2001, 2004, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#ifndef __JAVA_LANG_OBJECT_H__ +#define __JAVA_LANG_OBJECT_H__ + +#pragma interface + +#include <gcj/javaprims.h> + +extern "Java" +{ +// This class is mainly here as a kludge to get G++ to allocate two +// extra entries in each vtable. +struct _JvObjectPrefix +{ +protected: + // New ABI Compatibility Dummy, #1 and 2. + virtual void nacd_1 (void) {}; // This slot really contains the Class pointer. + // For IA64, the GC descriptor goes into the second word of the nacd1 descr. +# ifndef __ia64__ + virtual void nacd_2 (void) {}; // Actually the GC bitmap marking descriptor. +# endif +}; +} + +// Forward declarations for friends of java::lang::Object +void _Jv_MonitorEnter (jobject obj); +void _Jv_MonitorExit (jobject obj); +void _Jv_InitializeSyncMutex (void); +void _Jv_FinalizeObject (jobject obj); +bool _Jv_ObjectCheckMonitor (jobject obj); + +class java::lang::Object : public _JvObjectPrefix +{ +protected: + virtual void finalize (void); +public: + // Order must match order in Object.java. + jclass getClass (void); + virtual jint hashCode (void); + void notify (void); + void notifyAll (void); + void wait (jlong timeout, jint nanos); + virtual jboolean equals (jobject obj); + Object (void); + virtual jstring toString (void); + void wait (void); + void wait (jlong timeout); + + friend void ::_Jv_MonitorEnter (jobject obj); + friend void ::_Jv_MonitorExit (jobject obj); + friend void ::_Jv_InitializeSyncMutex (void); + friend void ::_Jv_FinalizeObject (jobject obj); + friend bool ::_Jv_ObjectCheckMonitor (jobject obj); + +#ifdef JV_MARKOBJ_DECL + friend JV_MARKOBJ_DECL; +#endif +#ifdef JV_MARKARRAY_DECL + friend JV_MARKARRAY_DECL; +#endif + + static java::lang::Class class$; + +protected: + virtual jobject clone (void); + +private: + // This does not actually refer to a Java object. Instead it is a + // placeholder for a piece of internal data (the synchronization + // information). +# ifndef JV_HASH_SYNCHRONIZATION + jobject sync_info; +# endif + + // Initialize the sync_info field. Not called with JV_HASH_SYNCHRONIZATION. + void sync_init (void); + +public: + virtual void throwNoSuchMethodError (void); +}; + +#endif /* __JAVA_LANG_OBJECT_H__ */ diff --git a/gcc-4.2.1/libjava/java/lang/Object.java b/gcc-4.2.1/libjava/java/lang/Object.java new file mode 100644 index 000000000..e81a48a9f --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Object.java @@ -0,0 +1,519 @@ +/* java.lang.Object - The universal superclass in Java + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * plus gcj compiler sources (to determine object layout) + * Status: Complete to version 1.1 + */ + +/** + * Object is the ultimate superclass of every class + * (excepting interfaces). When you define a class that + * does not extend any other class, it implicitly extends + * java.lang.Object. Also, an anonymous class based on + * an interface will extend Object. + * + * <p>It provides general-purpose methods that every single + * Object, regardless of race, sex or creed, implements. + * All of the public methods may be invoked on arrays or + * interfaces. The protected methods <code>clone</code> + * and <code>finalize</code> are not accessible on arrays + * or interfaces, but all array types have a public version + * of <code>clone</code> which is accessible. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Tom Tromey (tromey@cygnus.com) + */ +public class Object +{ + /** + * Called on an object by the Virtual Machine at most once, + * at some point after the Object is determined unreachable + * but before it is destroyed. You would think that this + * means it eventually is called on every Object, but this is + * not necessarily the case. If execution terminates + * abnormally, garbage collection does not always happen. + * Thus you cannot rely on this method to always work. + * For finer control over garbage collection, use references + * from the {@link java.lang.ref} package. + * + * <p>Virtual Machines are free to not call this method if + * they can determine that it does nothing important; for + * example, if your class extends Object and overrides + * finalize to do simply <code>super.finalize()</code>. + * + * <p>finalize() will be called by a {@link Thread} that has no + * locks on any Objects, and may be called concurrently. + * There are no guarantees on the order in which multiple + * objects are finalized. This means that finalize() is + * usually unsuited for performing actions that must be + * thread-safe, and that your implementation must be + * use defensive programming if it is to always work. + * + * <p>If an Exception is thrown from finalize() during garbage + * collection, it will be patently ignored and the Object will + * still be destroyed. + * + * <p>It is allowed, although not typical, for user code to call + * finalize() directly. User invocation does not affect whether + * automatic invocation will occur. It is also permitted, + * although not recommended, for a finalize() method to "revive" + * an object by making it reachable from normal code again. + * + * <p>Unlike constructors, finalize() does not get called + * for an object's superclass unless the implementation + * specifically calls <code>super.finalize()</code>. + * + * <p>The default implementation does nothing. + * + * @throws Throwable permits a subclass to throw anything in an + * overridden version; but the default throws nothing + * @see System#gc() + * @see System#runFinalizersOnExit(boolean) + * @see java.lang.ref + */ + // This must come first. See _JvObjectPrefix in Object.h. + protected void finalize () throws Throwable + { + } + + /** + * Returns the runtime {@link Class} of this Object. + * + * <p>The class object can also be obtained without a runtime + * instance by using the class literal, as in: + * <code>Foo.class</code>. Notice that the class literal + * also works on primitive types, making it useful for + * reflection purposes. + * + * @return the class of this Object + */ + public final native Class getClass(); + + /** + * Get a value that represents this Object, as uniquely as + * possible within the confines of an int. + * + * <p>There are some requirements on this method which + * subclasses must follow:<br> + * + * <ul> + * <li>Semantic equality implies identical hashcodes. In other + * words, if <code>a.equals(b)</code> is true, then + * <code>a.hashCode() == b.hashCode()</code> must be as well. + * However, the reverse is not necessarily true, and two + * objects may have the same hashcode without being equal.</li> + * <li>It must be consistent. Whichever value o.hashCode() + * returns on the first invocation must be the value + * returned on all later invocations as long as the object + * exists. Notice, however, that the result of hashCode may + * change between separate executions of a Virtual Machine, + * because it is not invoked on the same object.</li> + * </ul> + * + * <p>Notice that since <code>hashCode</code> is used in + * {@link java.util.Hashtable} and other hashing classes, + * a poor implementation will degrade the performance of hashing + * (so don't blindly implement it as returning a constant!). Also, + * if calculating the hash is time-consuming, a class may consider + * caching the results. + * + * <p>The default implementation returns + * <code>System.identityHashCode(this)</code> + * + * @return the hash code for this Object + * @see #equals(Object) + * @see System#identityHashCode(Object) + */ + public native int hashCode(); + + /** + * Wakes up one of the {@link Thread}s that has called + * <code>wait</code> on this Object. Only the owner + * of a lock on this Object may call this method. This lock + * is obtained by a <code>synchronized</code> method or statement. + * + * <p>The Thread to wake up is chosen arbitrarily. The + * awakened thread is not guaranteed to be the next thread + * to actually obtain the lock on this object. + * + * <p>This thread still holds a lock on the object, so it is + * typical to release the lock by exiting the synchronized + * code, calling wait(), or calling {@link Thread#sleep()}, so + * that the newly awakened thread can actually resume. The + * awakened thread will most likely be awakened with an + * {@link InterruptedException}, but that is not guaranteed. + * + * @throws IllegalMonitorStateException if this Thread + * does not own the lock on the Object + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final native void notify(); + + /** + * Wakes up all of the {@link Thread}s that have called + * <code>wait</code> on this Object. Only the owner + * of a lock on this Object may call this method. This lock + * is obtained by a <code>synchronized</code> method or statement. + * + * <p>There are no guarantees as to which thread will next + * obtain the lock on the object. + * + * <p>This thread still holds a lock on the object, so it is + * typical to release the lock by exiting the synchronized + * code, calling wait(), or calling {@link Thread#sleep()}, so + * that one of the newly awakened threads can actually resume. + * The resuming thread will most likely be awakened with an + * {@link InterruptedException}, but that is not guaranteed. + * + * @throws IllegalMonitorStateException if this Thread + * does not own the lock on the Object + * @see #notify() + * @see #wait() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final native void notifyAll(); + + /** + * Waits a specified amount of time (or indefinitely if + * the time specified is 0) for someone to call notify() + * or notifyAll() on this Object, waking up this Thread. + * + * <p>The Thread that calls wait must have a lock on this Object, + * obtained by a <code>synchronized</code> method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + * <p>Usually, this call will complete normally if the time + * expires, or abruptly with {@link InterruptedException} + * if another thread called notify, but neither result + * is guaranteed. + * + * <p>The waiting period is nowhere near as precise as + * nanoseconds; considering that even wait(int) is inaccurate, + * how much can you expect? But on supporting + * implementations, this offers somewhat more granularity + * than milliseconds. + * + * @param ms the number of milliseconds to wait (1,000 + * milliseconds = 1 second) + * @param ns the number of nanoseconds to wait over and + * above ms (1,000,000 nanoseconds = 1 millisecond) + * @throws IllegalArgumentException if ms < 0 or ns is not + * in the range 0 to 999,999 + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long) + * @see Thread + */ + public final native void wait(long timeout, int nanos) + throws InterruptedException; + + /** + * Determine whether this Object is semantically equal + * to another Object. + * + * <p>There are some fairly strict requirements on this + * method which subclasses must follow:<br> + * <ul> + * <li>It must be transitive. If <code>a.equals(b)</code> and + * <code>b.equals(c)</code>, then <code>a.equals(c)</code> + * must be true as well.</li> + * <li>It must be symmetric. <code>a.equals(b)</code> and + * <code>b.equals(a)</code> must have the same value.</li> + * <li>It must be reflexive. <code>a.equals(a)</code> must + * always be true.</li> + * <li>It must be consistent. Whichever value a.equals(b) + * returns on the first invocation must be the value + * returned on all later invocations.</li> + * <li><code>a.equals(null)</code> must be false.</li> + * <li>It must be consistent with hashCode(). That is, + * <code>a.equals(b)</code> must imply + * <code>a.hashCode() == b.hashCode()</code>. + * The reverse is not true; two objects that are not + * equal may have the same hashcode, but that has + * the potential to harm hashing performance.</li> + * </ul> + * + * <p>This is typically overridden to throw a {@link ClassCastException} + * if the argument is not comparable to the class performing + * the comparison, but that is not a requirement. It is legal + * for <code>a.equals(b)</code> to be true even though + * <code>a.getClass() != b.getClass()</code>. Also, it + * is typical to never cause a {@link NullPointerException}. + * + * <p>In general, the Collections API ({@link java.util}) use the + * <code>equals</code> method rather than the <code>==</code> + * operator to compare objects. However, {@link java.util.IdentityHashMap} + * is an exception to this rule, for its own good reasons. + * + * <p>The default implementation returns <code>this == o</code>. + * + * @param obj the Object to compare to + * @return whether this Object is semantically equal to another + * @see #hashCode() + */ + public boolean equals(Object obj) + { + return this == obj; + } + + /** + * The basic constructor. Object is special, because it has no + * superclass, so there is no call to super(). + * + * @throws OutOfMemoryError Technically, this constructor never + * throws an OutOfMemoryError, because the memory has + * already been allocated by this point. But as all + * instance creation expressions eventually trace back + * to this constructor, and creating an object allocates + * memory, we list that possibility here. + */ + public Object() + { + } + + /** + * Convert this Object to a human-readable String. + * There are no limits placed on how long this String + * should be or what it should contain. We suggest you + * make it as intuitive as possible to be able to place + * it into {@link java.io.PrintStream#println() System.out.println()} + * and such. + * + * <p>It is typical, but not required, to ensure that this method + * never completes abruptly with a {@link RuntimeException}. + * + * <p>This method will be called when performing string + * concatenation with this object. If the result is + * <code>null</code>, string concatenation will instead + * use <code>"null"</code>. + * + * <p>The default implementation returns + * <code>getClass().getName() + "@" + + * Integer.toHexString(hashCode())</code>. + * + * @return the String representing this Object, which may be null + * @throws OutOfMemoryError The default implementation creates a new + * String object, therefore it must allocate memory + * @see #getClass() + * @see #hashCode() + * @see Class#getName() + * @see Integer#toHexString(int) + */ + public String toString() + { + return getClass().getName() + '@' + Integer.toHexString(hashCode()); + } + + /** + * Waits indefinitely for notify() or notifyAll() to be + * called on the Object in question. Implementation is + * identical to wait(0). + * + * <p>The Thread that calls wait must have a lock on this Object, + * obtained by a <code>synchronized</code> method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + * <p>While it is typical that this method will complete abruptly + * with an {@link InterruptedException}, it is not guaranteed. So, + * it is typical to call wait inside an infinite loop:<br> + * + * <pre> + * try + * { + * while (true) + * lock.wait(); + * } + * catch (InterruptedException e) + * { + * } + * </pre> + * + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait(long) + * @see #wait(long, int) + * @see Thread + */ + public final void wait() throws InterruptedException + { + wait(0, 0); + } + + /** + * Waits a specified amount of time (or indefinitely if + * the time specified is 0) for someone to call notify() + * or notifyAll() on this Object, waking up this Thread. + * + * <p>The Thread that calls wait must have a lock on this Object, + * obtained by a <code>synchronized</code> method or statement. + * After calling wait, the thread loses the lock on this + * object until the method completes (abruptly or normally), + * at which time it regains the lock. All locks held on + * other objects remain in force, even though the thread is + * inactive. Therefore, caution must be used to avoid deadlock. + * + * <p>Usually, this call will complete normally if the time + * expires, or abruptly with {@link InterruptedException} + * if another thread called notify, but neither result + * is guaranteed. + * + * <p>The waiting period is only *roughly* the amount of time + * you requested. It cannot be exact because of the overhead + * of the call itself. Most Virtual Machiness treat the + * argument as a lower limit on the time spent waiting, but + * even that is not guaranteed. Besides, some other thread + * may hold the lock on the object when the time expires, so + * the current thread may still have to wait to reobtain the + * lock. + * + * @param timeout the minimum number of milliseconds to wait (1000 + * milliseconds = 1 second), or 0 for an indefinite wait + * @throws IllegalArgumentException if ms < 0 + * @throws IllegalMonitorStateException if this Thread + * does not own a lock on this Object + * @throws InterruptedException if some other Thread + * interrupts this Thread + * @see #notify() + * @see #notifyAll() + * @see #wait() + * @see #wait(long, int) + * @see Thread + */ + public final void wait(long timeout) throws InterruptedException + { + wait(timeout, 0); + } + + /** + * This method may be called to create a new copy of the + * Object. The typical behavior is as follows:<br> + * <ul> + * <li><code>o == o.clone()</code> is false</li> + * <li><code>o.getClass() == o.clone().getClass()</code> + * is true</li> + * <li><code>o.equals(o)</code> is true</li> + * </ul> + * + * <p>However, these are not strict requirements, and may + * be violated if necessary. Of the three requirements, the + * last is the most commonly violated, particularly if the + * subclass does not override {@link #equals(Object)}. + * + * <p>If the Object you call clone() on does not implement + * {@link Cloneable} (which is a placeholder interface), then + * a CloneNotSupportedException is thrown. Notice that + * Object does not implement Cloneable; this method exists + * as a convenience for subclasses that do. + * + * <p>Object's implementation of clone allocates space for the + * new Object using the correct class, without calling any + * constructors, and then fills in all of the new field values + * with the old field values. Thus, it is a shallow copy. + * However, subclasses are permitted to make a deep copy. + * + * <p>All array types implement Cloneable, and override + * this method as follows (it should never fail):<br> + * <pre> + * public Object clone() + * { + * try + * { + * super.clone(); + * } + * catch (CloneNotSupportedException e) + * { + * throw new InternalError(e.getMessage()); + * } + * } + * </pre> + * + * @return a copy of the Object + * @throws CloneNotSupportedException If this Object does not + * implement Cloneable + * @throws OutOfMemoryError Since cloning involves memory allocation, + * even though it may bypass constructors, you might run + * out of memory + * @see Cloneable + */ + protected native Object clone() throws CloneNotSupportedException; + + // This initializes the sync_info member. It is here for + // completeness (some day we'll be able to auto-generate Object.h). + private final native void sync_init(); + + // If we fail to find a method at class loading time we put the + // vtable index of this method in its place: any attempt to call + // that method will result in an error. + void throwNoSuchMethodError() + { + throw new NoSuchMethodError("in " + getClass()); + } + + // Note that we don't mention the sync_info field here. If we do, + // jc1 will not work correctly. +} diff --git a/gcc-4.2.1/libjava/java/lang/Package.java b/gcc-4.2.1/libjava/java/lang/Package.java new file mode 100644 index 000000000..0bf4315db --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Package.java @@ -0,0 +1,317 @@ +/* Package.java -- information about a package + Copyright (C) 2000, 2001, 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.net.URL; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; + + +/** + * Everything you ever wanted to know about a package. This class makes it + * possible to attach specification and implementation information to a + * package as explained in the + * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html#PackageVersionSpecification">Package Versioning Specification</a> + * section of the + * <a href="http://java.sun.com/products/jdk/1.3/docs/guide/versioning/spec/VersioningSpecification.html">Product Versioning Specification</a>. + * It also allows packages to be sealed with respect to the originating URL. + * + * <p>The most useful method is the <code>isCompatibleWith()</code> method that + * compares a desired version of a specification with the version of the + * specification as implemented by a package. A package is considered + * compatible with another version if the version of the specification is + * equal or higher then the requested version. Version numbers are represented + * as strings of positive numbers separated by dots (e.g. "1.2.0"). + * The first number is called the major number, the second the minor, + * the third the micro, etc. A version is considered higher then another + * version if it has a bigger major number then the another version or when + * the major numbers of the versions are equal if it has a bigger minor number + * then the other version, etc. (If a version has no minor, micro, etc numbers + * then they are considered the be 0.) + * + * @author Mark Wielaard (mark@klomp.org) + * @see ClassLoader#definePackage(String, String, String, String, String, + * String, String, URL) + * @since 1.2 + * @status updated to 1.4 + */ +public class Package +{ + /** The name of the Package */ + private final String name; + + /** The name if the implementation */ + private final String implTitle; + + /** The vendor that wrote this implementation */ + private final String implVendor; + + /** The version of this implementation */ + private final String implVersion; + + /** The name of the specification */ + private final String specTitle; + + /** The name of the specification designer */ + private final String specVendor; + + /** The version of this specification */ + private final String specVersion; + + /** If sealed the origin of the package classes, otherwise null */ + private final URL sealed; + + /** + * A package local constructor for the Package class. All parameters except + * the <code>name</code> of the package may be <code>null</code>. + * There are no public constructors defined for Package; this is a package + * local constructor that is used by java.lang.Classloader.definePackage(). + * + * @param name The name of the Package + * @param specTitle The name of the specification + * @param specVendor The name of the specification designer + * @param specVersion The version of this specification + * @param implTitle The name of the implementation + * @param implVendor The vendor that wrote this implementation + * @param implVersion The version of this implementation + * @param sealed If sealed the origin of the package classes + */ + Package(String name, + String specTitle, String specVendor, String specVersion, + String implTitle, String implVendor, String implVersion, URL sealed) + { + if (name == null) + throw new IllegalArgumentException("null Package name"); + + this.name = name; + this.implTitle = implTitle; + this.implVendor = implVendor; + this.implVersion = implVersion; + this.specTitle = specTitle; + this.specVendor = specVendor; + this.specVersion = specVersion; + this.sealed = sealed; + } + + /** + * Returns the Package name in dot-notation. + * + * @return the non-null package name + */ + public String getName() + { + return name; + } + + /** + * Returns the name of the specification, or null if unknown. + * + * @return the specification title + */ + public String getSpecificationTitle() + { + return specTitle; + } + + /** + * Returns the version of the specification, or null if unknown. + * + * @return the specification version + */ + public String getSpecificationVersion() + { + return specVersion; + } + + /** + * Returns the name of the specification designer, or null if unknown. + * + * @return the specification vendor + */ + public String getSpecificationVendor() + { + return specVendor; + } + + /** + * Returns the name of the implementation, or null if unknown. + * + * @return the implementation title + */ + public String getImplementationTitle() + { + return implTitle; + } + + /** + * Returns the version of this implementation, or null if unknown. + * + * @return the implementation version + */ + public String getImplementationVersion() + { + return implVersion; + } + + /** + * Returns the vendor that wrote this implementation, or null if unknown. + * + * @return the implementation vendor + */ + public String getImplementationVendor() + { + return implVendor; + } + + /** + * Returns true if this Package is sealed. + * + * @return true if the package is sealed + */ + public boolean isSealed() + { + return sealed != null; + } + + /** + * Returns true if this Package is sealed and the origin of the classes is + * the given URL. + * + * @param url the URL to test + * @return true if the package is sealed by this URL + * @throws NullPointerException if url is null + */ + public boolean isSealed(URL url) + { + return url.equals(sealed); + } + + /** + * Checks if the version of the specification is higher or at least as high + * as the desired version. Comparison is done by sequentially comparing + * dotted decimal numbers from the parameter and from + * <code>getSpecificationVersion</code>. + * + * @param version the (minimal) desired version of the specification + * + * @return true if the version is compatible, false otherwise + * + * @Throws NumberFormatException if either version string is invalid + * @throws NullPointerException if either version string is null + */ + public boolean isCompatibleWith(String version) + { + StringTokenizer versionTokens = new StringTokenizer(version, "."); + StringTokenizer specTokens = new StringTokenizer(specVersion, "."); + try + { + while (versionTokens.hasMoreElements()) + { + int vers = Integer.parseInt(versionTokens.nextToken()); + int spec = Integer.parseInt(specTokens.nextToken()); + if (spec < vers) + return false; + else if (spec > vers) + return true; + // They must be equal, next Token please! + } + } + catch (NoSuchElementException e) + { + // This must have been thrown by spec.nextToken() so return false. + return false; + } + // They must have been exactly the same version. + // Or the specVersion has more subversions. That is also good. + return true; + } + + /** + * Returns the named package if it is known by the callers class loader. + * It may return null if the package is unknown, when there is no + * information on that particular package available or when the callers + * classloader is null. + * + * @param name the name of the desired package + * @return the package by that name in the current ClassLoader + */ + public static Package getPackage(String name) + { + // Get the caller's classloader + ClassLoader cl = VMSecurityManager.currentClassLoader(Package.class); + return cl != null ? cl.getPackage(name) : VMClassLoader.getPackage(name); + } + + /** + * Returns all the packages that are known to the callers class loader. + * It may return an empty array if the classloader of the caller is null. + * + * @return an array of all known packages + */ + public static Package[] getPackages() + { + // Get the caller's classloader + Class c = VMSecurityManager.getClassContext(Package.class)[1]; + ClassLoader cl = c.getClassLoader(); + return cl != null ? cl.getPackages() : VMClassLoader.getPackages(); + } + + /** + * Returns the hashCode of the name of this package. + * + * @return the hash code + */ + public int hashCode() + { + return name.hashCode(); + } + + /** + * Returns a string representation of this package. It is specified to + * be <code>"package " + getName() + (getSpecificationTitle() == null + * ? "" : ", " + getSpecificationTitle()) + (getSpecificationVersion() + * == null ? "" : ", version " + getSpecificationVersion())</code>. + * + * @return the string representation of the package + */ + public String toString() + { + return ("package " + name + (specTitle == null ? "" : ", " + specTitle) + + (specVersion == null ? "" : ", version " + specVersion)); + } +} // class Package diff --git a/gcc-4.2.1/libjava/java/lang/PosixProcess.java b/gcc-4.2.1/libjava/java/lang/PosixProcess.java new file mode 100644 index 000000000..fbd6c4c8a --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/PosixProcess.java @@ -0,0 +1,475 @@ +// PosixProcess.java - Subclass of Process for POSIX systems. +/* Copyright (C) 1998, 1999, 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + + +/** + * @author Tom Tromey <tromey@cygnus.com> + * @date May 3, 1999 + * @author David Daney <ddaney@avtrex.com> Rewrote using + * ProcessManager + */ + +// This is entirely internal to our implementation. +// This file is copied to `ConcreteProcess.java' before compilation. +// Hence the class name apparently does not match the file name. +final class ConcreteProcess extends Process +{ + static class ProcessManager extends Thread + { + /** + * A list of {@link ConcreteProcess ConcreteProcesses} to be + * started. The queueLock object is used as the lock Object + * for all process related operations. To avoid dead lock + * ensure queueLock is obtained before ConcreteProcess. + */ + List queue = new LinkedList(); + private Map pidToProcess = new HashMap(); + private boolean ready = false; + private long reaperPID; + + ProcessManager() + { + super("ProcessManager"); + // Don't keep the (main) process from exiting on our account. + this.setDaemon(true); + } + + /** + * Get the ConcreteProcess object with the given pid and + * remove it from the map. This method is called from the + * native code for {@link #reap()). The mapping is removed so + * the ConcreteProcesses can be GCed after they terminate. + * + * @param p The pid of the process. + */ + private ConcreteProcess removeProcessFromMap(long p) + { + return (ConcreteProcess) pidToProcess.remove(new Long(p)); + } + + /** + * Put the given ConcreteProcess in the map using the Long + * value of its pid as the key. + * + * @param p The ConcreteProcess. + */ + void addProcessToMap(ConcreteProcess p) + { + pidToProcess.put(new Long(p.pid), p); + } + + /** + * Queue up the ConcreteProcess and awake the ProcessManager. + * The ProcessManager will start the ConcreteProcess from its + * thread so it can be reaped when it terminates. + * + * @param p The ConcreteProcess. + */ + void startExecuting(ConcreteProcess p) + { + synchronized (queueLock) + { + queue.add(p); + signalReaper(); // If blocked in waitForSignal(). + queueLock.notifyAll(); // If blocked in wait(); + } + } + + /** + * Block until the ProcessManager thread is ready to accept + * commands. + */ + void waitUntilReady() + { + synchronized (this) + { + try + { + while (! ready) + wait(); + } + catch (InterruptedException ie) + { + // Ignore. + } + } + } + + /** + * Main Process starting/reaping loop. + */ + public void run() + { + init(); + // Now ready to accept requests. + synchronized (this) + { + ready = true; + this.notifyAll(); + } + + for (;;) + { + try + { + synchronized (queueLock) + { + boolean haveMoreChildren = reap(); + if (! haveMoreChildren && queue.size() == 0) + { + // This reaper thread could exit, but we + // keep it alive for a while in case + // someone wants to start more Processes. + try + { + queueLock.wait(1000L); + if (queue.size() == 0) + { + processManager = null; + return; // Timed out. + } + } + catch (InterruptedException ie) + { + // Ignore and exit the thread. + return; + } + } + while (queue.size() > 0) + { + ConcreteProcess p = (ConcreteProcess) queue.remove(0); + p.spawn(this); + } + } + + // Wait for a SIGCHLD from either an exiting + // process or the startExecuting() method. This + // is done outside of the synchronized block to + // allow other threads to enter and submit more + // jobs. + waitForSignal(); + } + catch (Exception ex) + { + ex.printStackTrace(System.err); + } + } + } + + /** + * Setup native signal handlers and other housekeeping things. + * + */ + private native void init(); + + /** + * Block waiting for SIGCHLD. + * + */ + private native void waitForSignal(); + + /** + * Try to reap as many children as possible without blocking. + * + * @return true if more live children exist. + * + */ + private native boolean reap(); + + /** + * Send SIGCHLD to the reaper thread. + */ + private native void signalReaper(); + } + + public void destroy() + { + // Synchronized on the queueLock. This ensures that the reaper + // thread cannot be doing a wait() on the child. + // Otherwise there would be a race where the OS could + // create a process with the same pid between the wait() + // and the update of the state which would cause a kill to + // the wrong process. + synchronized (queueLock) + { + synchronized (this) + { + // If there is no ProcessManager we cannot kill. + if (state != STATE_TERMINATED) + { + if (processManager == null) + throw new InternalError(); + nativeDestroy(); + } + } + } + } + + private native void nativeDestroy(); + + public int exitValue() + { + synchronized (this) + { + if (state != STATE_TERMINATED) + throw new IllegalThreadStateException("Process has not exited"); + } + return status; + } + + /** + * Called by native code when process exits. + * + * Already synchronized (this). Close any streams that we can to + * conserve file descriptors. + * + * The outputStream can be closed as any future writes will + * generate an IOException due to EPIPE. + * + * The inputStream and errorStream can only be closed if the user + * has not obtained a reference to them AND they have no bytes + * available. Since the process has terminated they will never have + * any more data available and can safely be replaced by + * EOFInputStreams. + */ + void processTerminationCleanup() + { + try + { + outputStream.close(); + } + catch (IOException ioe) + { + // Ignore. + } + try + { + if (returnedErrorStream == null && errorStream.available() == 0) + { + errorStream.close(); + errorStream = null; + } + } + catch (IOException ioe) + { + // Ignore. + } + try + { + if (returnedInputStream == null && inputStream.available() == 0) + { + inputStream.close(); + inputStream = null; + } + } + catch (IOException ioe) + { + // Ignore. + } + } + + public synchronized InputStream getErrorStream() + { + if (returnedErrorStream != null) + return returnedErrorStream; + + if (errorStream == null) + returnedErrorStream = EOFInputStream.instance; + else + returnedErrorStream = errorStream; + + return returnedErrorStream; + } + + public synchronized InputStream getInputStream() + { + if (returnedInputStream != null) + return returnedInputStream; + + if (inputStream == null) + returnedInputStream = EOFInputStream.instance; + else + returnedInputStream = inputStream; + + return returnedInputStream; + } + + public OutputStream getOutputStream() + { + return outputStream; + } + + public int waitFor() throws InterruptedException + { + synchronized (this) + { + while (state != STATE_TERMINATED) + wait(); + } + return status; + } + + /** + * Start this process running. This should only be called by the + * ProcessManager. + * + * @param pm The ProcessManager that made the call. + */ + void spawn(ProcessManager pm) + { + synchronized (this) + { + // Do the fork/exec magic. + nativeSpawn(); + // There is no race with reap() in the pidToProcess map + // because this is always called from the same thread + // doing the reaping. + pm.addProcessToMap(this); + state = STATE_RUNNING; + // Notify anybody waiting on state change. + this.notifyAll(); + } + } + + /** + * Do the fork and exec. + */ + private native void nativeSpawn(); + + // This file is copied to `ConcreteProcess.java' before + // compilation. Hence the constructor name apparently does not + // match the file name. + ConcreteProcess(String[] progarray, String[] envp, File dir) + throws IOException + { + // Check to ensure there is something to run, and avoid + // dereferencing null pointers in native code. + if (progarray[0] == null) + throw new NullPointerException(); + + this.progarray = progarray; + this.envp = envp; + this.dir = dir; + + // Start a ProcessManager if there is not one already running. + synchronized (queueLock) + { + if (processManager == null) + { + processManager = new ProcessManager(); + processManager.start(); + processManager.waitUntilReady(); + } + + // Queue this ConcreteProcess for starting by the ProcessManager. + processManager.startExecuting(this); + } + + // Wait until ProcessManager has started us. + synchronized (this) + { + while (state == STATE_WAITING_TO_START) + { + try + { + wait(); + } + catch (InterruptedException ie) + { + // FIXME: What to do when interrupted while blocking in a constructor? + // Ignore. + } + } + } + + // If there was a problem, re-throw it. + if (exception != null) + { + if (exception instanceof IOException) + { + IOException ioe = new IOException(exception.toString()); + ioe.initCause(exception); + throw ioe; + } + + // Not an IOException. Something bad happened. + InternalError ie = new InternalError(exception.toString()); + ie.initCause(exception); + throw ie; + } + + // If we get here, all is well, the Process has started. + } + + private String[] progarray; + private String[] envp; + private File dir; + + /** Set by the ProcessManager on problems starting. */ + private Throwable exception; + + /** The process id. This is cast to a pid_t on the native side. */ + private long pid; + + // FIXME: Why doesn't the friend declaration in ConcreteProcess.h + // allow ConcreteProcess$ProcessManager native code access these + // when they are private? + + /** Before the process is forked. */ + static final int STATE_WAITING_TO_START = 0; + + /** After the fork. */ + static final int STATE_RUNNING = 1; + + /** After exit code has been collected. */ + static final int STATE_TERMINATED = 2; + + /** One of STATE_WAITING_TO_START, STATE_RUNNING, STATE_TERMINATED. */ + int state; + + /** The exit status, if the child has exited. */ + int status; + + /** The streams. */ + private InputStream errorStream; + private InputStream inputStream; + private OutputStream outputStream; + + /** InputStreams obtained by the user. Not null indicates that the + * user has obtained the stream. + */ + private InputStream returnedErrorStream; + private InputStream returnedInputStream; + + /** + * Lock Object for all processManager related locking. + */ + private static Object queueLock = new Object(); + private static ProcessManager processManager; + + static class EOFInputStream extends InputStream + { + static EOFInputStream instance = new EOFInputStream(); + public int read() + { + return -1; + } + } +} diff --git a/gcc-4.2.1/libjava/java/lang/Runtime.java b/gcc-4.2.1/libjava/java/lang/Runtime.java new file mode 100644 index 000000000..3466f19f2 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Runtime.java @@ -0,0 +1,747 @@ +/* Runtime.java -- access to the VM process + Copyright (C) 1998, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.classpath.SystemProperties; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; + +/** + * Runtime represents the Virtual Machine. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Jeroen Frijters + */ +// No idea why this class isn't final, since you can't build a subclass! +public class Runtime +{ + /** + * The library path, to search when loading libraries. We can also safely use + * this as a lock for synchronization. + */ + private final String[] libpath; + + static + { + init(); + } + + /** + * The thread that started the exit sequence. Access to this field must + * be thread-safe; lock on libpath to avoid deadlock with user code. + * <code>runFinalization()</code> may want to look at this to see if ALL + * finalizers should be run, because the virtual machine is about to halt. + */ + private Thread exitSequence; + + /** + * All shutdown hooks. This is initialized lazily, and set to null once all + * shutdown hooks have run. Access to this field must be thread-safe; lock + * on libpath to avoid deadlock with user code. + */ + private Set shutdownHooks; + + /** True if we should finalize on exit. */ + private boolean finalizeOnExit; + + /** + * The one and only runtime instance. + */ + private static final Runtime current = new Runtime(); + + /** + * Not instantiable by a user, this should only create one instance. + */ + private Runtime() + { + if (current != null) + throw new InternalError("Attempt to recreate Runtime"); + + // We don't use libpath in the libgcj implementation. We still + // set it to something to allow the various synchronizations to + // work. + libpath = new String[0]; + } + + /** + * Get the current Runtime object for this JVM. This is necessary to access + * the many instance methods of this class. + * + * @return the current Runtime object + */ + public static Runtime getRuntime() + { + return current; + } + + /** + * Exit the Java runtime. This method will either throw a SecurityException + * or it will never return. The status code is returned to the system; often + * a non-zero status code indicates an abnormal exit. Of course, there is a + * security check, <code>checkExit(status)</code>. + * + * <p>First, all shutdown hooks are run, in unspecified order, and + * concurrently. Next, if finalization on exit has been enabled, all pending + * finalizers are run. Finally, the system calls <code>halt</code>.</p> + * + * <p>If this is run a second time after shutdown has already started, there + * are two actions. If shutdown hooks are still executing, it blocks + * indefinitely. Otherwise, if the status is nonzero it halts immediately; + * if it is zero, it blocks indefinitely. This is typically called by + * <code>System.exit</code>.</p> + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @see #addShutdownHook(Thread) + * @see #runFinalizersOnExit(boolean) + * @see #runFinalization() + * @see #halt(int) + */ + public void exit(int status) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(status); + exitNoChecks(status); + } + + // Accessor to avoid adding a vtable slot. + static void exitNoChecksAccessor(int status) + { + current.exitNoChecks(status); + } + + // Private since we can't add a vtable slot in 4.1.x. + private void exitNoChecks(int status) + { + if (runShutdownHooks()) + exitInternal(status); + + // Someone else already called runShutdownHooks(). + // Make sure we are not/no longer in the shutdownHooks set. + // And wait till the thread that is calling runShutdownHooks() finishes. + synchronized (libpath) + { + if (shutdownHooks != null) + { + shutdownHooks.remove(Thread.currentThread()); + // Interrupt the exit sequence thread, in case it was waiting + // inside a join on our thread. + exitSequence.interrupt(); + // Shutdown hooks are still running, so we clear status to + // make sure we don't halt. + status = 0; + } + } + + // If exit() is called again after the shutdown hooks have run, but + // while finalization for exit is going on and the status is non-zero + // we halt immediately. + if (status != 0) + exitInternal(status); + + while (true) + try + { + exitSequence.join(); + } + catch (InterruptedException e) + { + // Ignore, we've suspended indefinitely to let all shutdown + // hooks complete, and to let any non-zero exits through, because + // this is a duplicate call to exit(0). + } + } + + /** + * On first invocation, run all the shutdown hooks and return true. + * Any subsequent invocations will simply return false. + * Note that it is package accessible so that VMRuntime can call it + * when VM exit is not triggered by a call to Runtime.exit(). + * + * @return was the current thread the first one to call this method? + */ + boolean runShutdownHooks() + { + boolean first = false; + synchronized (libpath) // Synch on libpath, not this, to avoid deadlock. + { + if (exitSequence == null) + { + first = true; + exitSequence = Thread.currentThread(); + if (shutdownHooks != null) + { + Iterator i = shutdownHooks.iterator(); + while (i.hasNext()) // Start all shutdown hooks. + try + { + ((Thread) i.next()).start(); + } + catch (IllegalThreadStateException e) + { + i.remove(); + } + } + } + } + if (first) + { + if (shutdownHooks != null) + { + // Check progress of all shutdown hooks. As a hook completes, + // remove it from the set. If a hook calls exit, it removes + // itself from the set, then waits indefinitely on the + // exitSequence thread. Once the set is empty, set it to null to + // signal all finalizer threads that halt may be called. + while (true) + { + Thread[] hooks; + synchronized (libpath) + { + hooks = new Thread[shutdownHooks.size()]; + shutdownHooks.toArray(hooks); + } + if (hooks.length == 0) + break; + for (int i = 0; i < hooks.length; i++) + { + try + { + synchronized (libpath) + { + if (!shutdownHooks.contains(hooks[i])) + continue; + } + hooks[i].join(); + synchronized (libpath) + { + shutdownHooks.remove(hooks[i]); + } + } + catch (InterruptedException x) + { + // continue waiting on the next thread + } + } + } + synchronized (libpath) + { + shutdownHooks = null; + } + } + // Run finalization on all finalizable objects (even if they are + // still reachable). + runFinalizationForExit(); + } + return first; + } + + /** + * Register a new shutdown hook. This is invoked when the program exits + * normally (because all non-daemon threads ended, or because + * <code>System.exit</code> was invoked), or when the user terminates + * the virtual machine (such as by typing ^C, or logging off). There is + * a security check to add hooks, + * <code>RuntimePermission("shutdownHooks")</code>. + * + * <p>The hook must be an initialized, but unstarted Thread. The threads + * are run concurrently, and started in an arbitrary order; and user + * threads or daemons may still be running. Once shutdown hooks have + * started, they must all complete, or else you must use <code>halt</code>, + * to actually finish the shutdown sequence. Attempts to modify hooks + * after shutdown has started result in IllegalStateExceptions.</p> + * + * <p>It is imperative that you code shutdown hooks defensively, as you + * do not want to deadlock, and have no idea what other hooks will be + * running concurrently. It is also a good idea to finish quickly, as the + * virtual machine really wants to shut down!</p> + * + * <p>There are no guarantees that such hooks will run, as there are ways + * to forcibly kill a process. But in such a drastic case, shutdown hooks + * would do little for you in the first place.</p> + * + * @param hook an initialized, unstarted Thread + * @throws IllegalArgumentException if the hook is already registered or run + * @throws IllegalStateException if the virtual machine is already in + * the shutdown sequence + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #removeShutdownHook(Thread) + * @see #exit(int) + * @see #halt(int) + */ + public void addShutdownHook(Thread hook) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + if (hook.isAlive() || hook.getThreadGroup() == null) + throw new IllegalArgumentException("The hook thread " + hook + " must not have been already run or started"); + synchronized (libpath) + { + if (exitSequence != null) + throw new IllegalStateException("The Virtual Machine is exiting. It is not possible anymore to add any hooks"); + if (shutdownHooks == null) + shutdownHooks = new HashSet(); // Lazy initialization. + if (! shutdownHooks.add(hook)) + throw new IllegalArgumentException(hook.toString() + " had already been inserted"); + } + } + + /** + * De-register a shutdown hook. As when you registered it, there is a + * security check to remove hooks, + * <code>RuntimePermission("shutdownHooks")</code>. + * + * @param hook the hook to remove + * @return true if the hook was successfully removed, false if it was not + * registered in the first place + * @throws IllegalStateException if the virtual machine is already in + * the shutdown sequence + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #addShutdownHook(Thread) + * @see #exit(int) + * @see #halt(int) + */ + public boolean removeShutdownHook(Thread hook) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkPermission(new RuntimePermission("shutdownHooks")); + synchronized (libpath) + { + if (exitSequence != null) + throw new IllegalStateException(); + if (shutdownHooks != null) + return shutdownHooks.remove(hook); + } + return false; + } + + /** + * Forcibly terminate the virtual machine. This call never returns. It is + * much more severe than <code>exit</code>, as it bypasses all shutdown + * hooks and initializers. Use caution in calling this! Of course, there is + * a security check, <code>checkExit(status)</code>. + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @since 1.3 + * @see #exit(int) + * @see #addShutdownHook(Thread) + */ + public void halt(int status) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(status); + exitInternal(status); + } + + /** + * Tell the VM to run the finalize() method on every single Object before + * it exits. Note that the JVM may still exit abnormally and not perform + * this, so you still don't have a guarantee. And besides that, this is + * inherently unsafe in multi-threaded code, as it may result in deadlock + * as multiple threads compete to manipulate objects. This value defaults to + * <code>false</code>. There is a security check, <code>checkExit(0)</code>. + * + * @param finalizeOnExit whether to finalize all Objects on exit + * @throws SecurityException if permission is denied + * @see #exit(int) + * @see #gc() + * @since 1.1 + * @deprecated never rely on finalizers to do a clean, thread-safe, + * mop-up from your code + */ + public static void runFinalizersOnExit(boolean finalizeOnExit) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExit(0); + current.finalizeOnExit = finalizeOnExit; + } + + /** + * Create a new subprocess with the specified command line. Calls + * <code>exec(cmdline, null, null)</code>. A security check is performed, + * <code>checkExec</code>. + * + * @param cmdline the command to call + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null + * @throws IndexOutOfBoundsException if cmdline is "" + */ + public Process exec(String cmdline) throws IOException + { + return exec(cmdline, null, null); + } + + /** + * Create a new subprocess with the specified command line and environment. + * If the environment is null, the process inherits the environment of + * this process. Calls <code>exec(cmdline, env, null)</code>. A security + * check is performed, <code>checkExec</code>. + * + * @param cmdline the command to call + * @param env the environment to use, in the format name=value + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null, or env has null entries + * @throws IndexOutOfBoundsException if cmdline is "" + */ + public Process exec(String cmdline, String[] env) throws IOException + { + return exec(cmdline, env, null); + } + + /** + * Create a new subprocess with the specified command line, environment, and + * working directory. If the environment is null, the process inherits the + * environment of this process. If the directory is null, the process uses + * the current working directory. This splits cmdline into an array, using + * the default StringTokenizer, then calls + * <code>exec(cmdArray, env, dir)</code>. A security check is performed, + * <code>checkExec</code>. + * + * @param cmdline the command to call + * @param env the environment to use, in the format name=value + * @param dir the working directory to use + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmdline is null, or env has null entries + * @throws IndexOutOfBoundsException if cmdline is "" + * @since 1.3 + */ + public Process exec(String cmdline, String[] env, File dir) + throws IOException + { + StringTokenizer t = new StringTokenizer(cmdline); + String[] cmd = new String[t.countTokens()]; + for (int i = 0; i < cmd.length; i++) + cmd[i] = t.nextToken(); + return exec(cmd, env, dir); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized. Calls <code>exec(cmd, null, null)</code>. A security check + * is performed, <code>checkExec</code>. + * + * @param cmd the command to call + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or has null entries + * @throws IndexOutOfBoundsException if cmd is length 0 + */ + public Process exec(String[] cmd) throws IOException + { + return exec(cmd, null, null); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized, and specified environment. If the environment is null, the + * process inherits the environment of this process. Calls + * <code>exec(cmd, env, null)</code>. A security check is performed, + * <code>checkExec</code>. + * + * @param cmd the command to call + * @param env the environment to use, in the format name=value + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or cmd or env has null + * entries + * @throws IndexOutOfBoundsException if cmd is length 0 + */ + public Process exec(String[] cmd, String[] env) throws IOException + { + return exec(cmd, env, null); + } + + /** + * Create a new subprocess with the specified command line, already + * tokenized, and the specified environment and working directory. If the + * environment is null, the process inherits the environment of this + * process. If the directory is null, the process uses the current working + * directory. A security check is performed, <code>checkExec</code>. + * + * @param cmd the command to call + * @param env the environment to use, in the format name=value + * @param dir the working directory to use + * @return the Process object + * @throws SecurityException if permission is denied + * @throws IOException if an I/O error occurs + * @throws NullPointerException if cmd is null, or cmd or env has null + * entries + * @throws IndexOutOfBoundsException if cmd is length 0 + * @since 1.3 + */ + public Process exec(String[] cmd, String[] env, File dir) + throws IOException + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkExec(cmd[0]); + return execInternal(cmd, env, dir); + } + + /** + * Returns the number of available processors currently available to the + * virtual machine. This number may change over time; so a multi-processor + * program want to poll this to determine maximal resource usage. + * + * @return the number of processors available, at least 1 + */ + public native int availableProcessors(); + + /** + * Find out how much memory is still free for allocating Objects on the heap. + * + * @return the number of bytes of free memory for more Objects + */ + public native long freeMemory(); + + /** + * Find out how much memory total is available on the heap for allocating + * Objects. + * + * @return the total number of bytes of memory for Objects + */ + public native long totalMemory(); + + /** + * Returns the maximum amount of memory the virtual machine can attempt to + * use. This may be <code>Long.MAX_VALUE</code> if there is no inherent + * limit (or if you really do have a 8 exabyte memory!). + * + * @return the maximum number of bytes the virtual machine will attempt + * to allocate + */ + public native long maxMemory(); + + /** + * Run the garbage collector. This method is more of a suggestion than + * anything. All this method guarantees is that the garbage collector will + * have "done its best" by the time it returns. Notice that garbage + * collection takes place even without calling this method. + */ + public native void gc(); + + /** + * Run finalization on all Objects that are waiting to be finalized. Again, + * a suggestion, though a stronger one than {@link #gc()}. This calls the + * <code>finalize</code> method of all objects waiting to be collected. + * + * @see #finalize() + */ + public native void runFinalization(); + + /** + * Tell the VM to trace every bytecode instruction that executes (print out + * a trace of it). No guarantees are made as to where it will be printed, + * and the VM is allowed to ignore this request. + * + * @param on whether to turn instruction tracing on + */ + public native void traceInstructions(boolean on); + + /** + * Tell the VM to trace every method call that executes (print out a trace + * of it). No guarantees are made as to where it will be printed, and the + * VM is allowed to ignore this request. + * + * @param on whether to turn method tracing on + */ + public native void traceMethodCalls(boolean on); + + /** + * Load a native library using the system-dependent filename. This is similar + * to loadLibrary, except the only name mangling done is inserting "_g" + * before the final ".so" if the VM was invoked by the name "java_g". There + * may be a security check, of <code>checkLink</code>. + * + * @param filename the file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + */ + public void load(String filename) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkLink(filename); + _load(filename, false); + } + + /** + * Load a native library using a system-independent "short name" for the + * library. It will be transformed to a correct filename in a + * system-dependent manner (for example, in Windows, "mylib" will be turned + * into "mylib.dll"). This is done as follows: if the context that called + * load has a ClassLoader cl, then <code>cl.findLibrary(libpath)</code> is + * used to convert the name. If that result was null, or there was no class + * loader, this searches each directory of the system property + * <code>java.library.path</code> for a file named + * <code>System.mapLibraryName(libname)</code>. There may be a security + * check, of <code>checkLink</code>. + * + * @param libname the library to load + * + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the library is not found + * + * @see System#mapLibraryName(String) + * @see ClassLoader#findLibrary(String) + */ + public void loadLibrary(String libname) + { + // This is different from the Classpath implementation, but I + // believe it is more correct. + SecurityManager sm = SecurityManager.current; // Be thread-safe! + if (sm != null) + sm.checkLink(libname); + _load(libname, true); + } + + /** + * Return a localized version of this InputStream, meaning all characters + * are localized before they come out the other end. + * + * @param in the stream to localize + * @return the localized stream + * @deprecated <code>InputStreamReader</code> is the preferred way to read + * local encodings + */ + public InputStream getLocalizedInputStream(InputStream in) + { + return in; + } + + /** + * Return a localized version of this OutputStream, meaning all characters + * are localized before they are sent to the other end. + * + * @param out the stream to localize + * @return the localized stream + * @deprecated <code>OutputStreamWriter</code> is the preferred way to write + * local encodings + */ + public OutputStream getLocalizedOutputStream(OutputStream out) + { + return out; + } + + /** + * Native method that actually shuts down the virtual machine. + * + * @param status the status to end the process with + */ + native void exitInternal(int status); + + /** + * Load a file. If it has already been loaded, do nothing. The name has + * already been mapped to a true filename. + * + * @param filename the file to load + * @param do_search True if we should search the load path for the file + */ + native void _load(String filename, boolean do_search); + + /** + *This is a helper function for the ClassLoader which can load + * compiled libraries. Returns true if library (which is just the + * base name -- path searching is done by this function) was loaded, + * false otherwise. + */ + native boolean loadLibraryInternal(String libname); + + /** + * A helper for Runtime static initializer which does some internal native + * initialization. + */ + private static native void init (); + + /** + * Run finalizers when exiting. + */ + private native void runFinalizationForExit(); + + /** + * Map a system-independent "short name" to the full file name, and append + * it to the path. + * XXX This method is being replaced by System.mapLibraryName. + * + * @param pathname the path + * @param libname the short version of the library name + * @return the full filename + */ + static native String nativeGetLibname(String pathname, String libname); + + /** + * Execute a process. The command line has already been tokenized, and + * the environment should contain name=value mappings. If directory is null, + * use the current working directory; otherwise start the process in that + * directory. + * + * @param cmd the non-null command tokens + * @param env the non-null environment setup + * @param dir the directory to use, may be null + * @return the newly created process + * @throws NullPointerException if cmd or env have null elements + * @throws IOException if the exec fails + */ + native Process execInternal(String[] cmd, String[] env, File dir) + throws IOException; +} // class Runtime diff --git a/gcc-4.2.1/libjava/java/lang/SecurityManager.java b/gcc-4.2.1/libjava/java/lang/SecurityManager.java new file mode 100644 index 000000000..c803c5b85 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/SecurityManager.java @@ -0,0 +1,1057 @@ +/* SecurityManager.java -- security checks for privileged actions + Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import java.awt.AWTPermission; +import java.io.File; +import java.io.FileDescriptor; +import java.io.FilePermission; +import java.lang.reflect.Member; +import java.net.InetAddress; +import java.net.SocketPermission; +import java.security.AccessController; +import java.security.AccessControlContext; +import java.security.AllPermission; +import java.security.Permission; +import java.security.PrivilegedAction; +import java.security.Security; +import java.security.SecurityPermission; +import java.util.PropertyPermission; +import java.util.StringTokenizer; + +/** + * SecurityManager is a class you can extend to create your own Java + * security policy. By default, there is no SecurityManager installed in + * 1.1, which means that all things are permitted to all people. The security + * manager, if set, is consulted before doing anything with potentially + * dangerous results, and throws a <code>SecurityException</code> if the + * action is forbidden. + * + * <p>A typical check is as follows, just before the dangerous operation:<br> + * <pre> + * SecurityManager sm = System.getSecurityManager(); + * if (sm != null) + * sm.checkABC(<em>argument</em>, ...); + * </pre> + * Note that this is thread-safe, by caching the security manager in a local + * variable rather than risking a NullPointerException if the mangager is + * changed between the check for null and before the permission check. + * + * <p>The special method <code>checkPermission</code> is a catchall, and + * the default implementation calls + * <code>AccessController.checkPermission</code>. In fact, all the other + * methods default to calling checkPermission. + * + * <p>Sometimes, the security check needs to happen from a different context, + * such as when called from a worker thread. In such cases, use + * <code>getSecurityContext</code> to take a snapshot that can be passed + * to the worker thread:<br> + * <pre> + * Object context = null; + * SecurityManager sm = System.getSecurityManager(); + * if (sm != null) + * context = sm.getSecurityContext(); // defaults to an AccessControlContext + * // now, in worker thread + * if (sm != null) + * sm.checkPermission(permission, context); + * </pre> + * + * <p>Permissions fall into these categories: File, Socket, Net, Security, + * Runtime, Property, AWT, Reflect, and Serializable. Each of these + * permissions have a property naming convention, that follows a hierarchical + * naming convention, to make it easy to grant or deny several permissions + * at once. Some permissions also take a list of permitted actions, such + * as "read" or "write", to fine-tune control even more. The permission + * <code>java.security.AllPermission</code> grants all permissions. + * + * <p>The default methods in this class deny all things to all people. You + * must explicitly grant permission for anything you want to be legal when + * subclassing this class. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @see ClassLoader + * @see SecurityException + * @see #checkTopLevelWindow(Object) + * @see System#getSecurityManager() + * @see System#setSecurityManager(SecurityManager) + * @see AccessController + * @see AccessControlContext + * @see AccessControlException + * @see Permission + * @see BasicPermission + * @see java.io.FilePermission + * @see java.net.SocketPermission + * @see java.util.PropertyPermission + * @see RuntimePermission + * @see java.awt.AWTPermission + * @see Policy + * @see SecurityPermission + * @see ProtectionDomain + * @since 1.0 + * @status still missing 1.4 functionality + */ +public class SecurityManager +{ + /** + * The current security manager. This is located here instead of in + * System, to avoid security problems, as well as bootstrap issues. + * Make sure to access it in a thread-safe manner; it is package visible + * to avoid overhead in java.lang. + */ + static volatile SecurityManager current; + + /** + * Tells whether or not the SecurityManager is currently performing a + * security check. + * @deprecated Use {@link #checkPermission(Permission)} instead. + */ + protected boolean inCheck; + + /** + * Construct a new security manager. There may be a security check, of + * <code>RuntimePermission("createSecurityManager")</code>. + * + * @throws SecurityException if permission is denied + */ + public SecurityManager() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("createSecurityManager")); + } + + /** + * Tells whether or not the SecurityManager is currently performing a + * security check. + * + * @return true if the SecurityManager is in a security check + * @see #inCheck + * @deprecated use {@link #checkPermission(Permission)} instead + */ + public boolean getInCheck() + { + return inCheck; + } + + /** + * Get a list of all the classes currently executing methods on the Java + * stack. getClassContext()[0] is the currently executing method (ie. the + * class that CALLED getClassContext, not SecurityManager). + * + * @return an array of classes on the Java execution stack + */ + protected Class[] getClassContext() + { + return VMSecurityManager.getClassContext(SecurityManager.class); + } + + /** + * Find the ClassLoader of the first non-system class on the execution + * stack. A non-system class is one whose ClassLoader is not equal to + * {@link ClassLoader#getSystemClassLoader()} or its ancestors. This + * will return null in three cases: + * + * <ul> + * <li>All methods on the stack are from system classes</li> + * <li>All methods on the stack up to the first "privileged" caller, as + * created by {@link AccessController#doPrivileged(PrivilegedAction)}, + * are from system classes</li> + * <li>A check of <code>java.security.AllPermission</code> succeeds.</li> + * </ul> + * + * @return the most recent non-system ClassLoader on the execution stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected ClassLoader currentClassLoader() + { + return VMSecurityManager.currentClassLoader(SecurityManager.class); + } + + /** + * Find the first non-system class on the execution stack. A non-system + * class is one whose ClassLoader is not equal to + * {@link ClassLoader#getSystemClassLoader()} or its ancestors. This + * will return null in three cases: + * + * <ul> + * <li>All methods on the stack are from system classes</li> + * <li>All methods on the stack up to the first "privileged" caller, as + * created by {@link AccessController#doPrivileged(PrivilegedAction)}, + * are from system classes</li> + * <li>A check of <code>java.security.AllPermission</code> succeeds.</li> + * </ul> + * + * @return the most recent non-system Class on the execution stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected Class currentLoadedClass() + { + int i = classLoaderDepth(); + return i >= 0 ? getClassContext()[i] : null; + } + + /** + * Get the depth of a particular class on the execution stack. + * + * @param className the fully-qualified name to search for + * @return the index of the class on the stack, or -1 + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected int classDepth(String className) + { + Class[] c = getClassContext(); + for (int i = 0; i < c.length; i++) + if (className.equals(c[i].getName())) + return i; + return -1; + } + + /** + * Get the depth on the execution stack of the most recent non-system class. + * A non-system class is one whose ClassLoader is not equal to + * {@link ClassLoader#getSystemClassLoader()} or its ancestors. This + * will return -1 in three cases: + * + * <ul> + * <li>All methods on the stack are from system classes</li> + * <li>All methods on the stack up to the first "privileged" caller, as + * created by {@link AccessController#doPrivileged(PrivilegedAction)}, + * are from system classes</li> + * <li>A check of <code>java.security.AllPermission</code> succeeds.</li> + * </ul> + * + * @return the index of the most recent non-system Class on the stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected int classLoaderDepth() + { + try + { + checkPermission(new AllPermission()); + } + catch (SecurityException e) + { + Class[] c = getClassContext(); + for (int i = 0; i < c.length; i++) + if (c[i].getClassLoader() != null) + // XXX Check if c[i] is AccessController, or a system class. + return i; + } + return -1; + } + + /** + * Tell whether the specified class is on the execution stack. + * + * @param className the fully-qualified name of the class to find + * @return whether the specified class is on the execution stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected boolean inClass(String className) + { + return classDepth(className) != -1; + } + + /** + * Tell whether there is a class loaded with an explicit ClassLoader on + * the stack. + * + * @return whether a class with an explicit ClassLoader is on the stack + * @deprecated use {@link #checkPermission(Permission)} instead + */ + protected boolean inClassLoader() + { + return classLoaderDepth() != -1; + } + + /** + * Get an implementation-dependent Object that contains enough information + * about the current environment to be able to perform standard security + * checks later. This is used by trusted methods that need to verify that + * their callers have sufficient access to perform certain operations. + * + * <p>Currently the only methods that use this are checkRead() and + * checkConnect(). The default implementation returns an + * <code>AccessControlContext</code>. + * + * @return a security context + * @see #checkConnect(String, int, Object) + * @see #checkRead(String, Object) + * @see AccessControlContext + * @see AccessController#getContext() + */ + public Object getSecurityContext() + { + return AccessController.getContext(); + } + + /** + * Check if the current thread is allowed to perform an operation that + * requires the specified <code>Permission</code>. This defaults to + * <code>AccessController.checkPermission</code>. + * + * @param perm the <code>Permission</code> required + * @throws SecurityException if permission is denied + * @throws NullPointerException if perm is null + * @since 1.2 + */ + public void checkPermission(Permission perm) + { + AccessController.checkPermission(perm); + } + + /** + * Check if the current thread is allowed to perform an operation that + * requires the specified <code>Permission</code>. This is done in a + * context previously returned by <code>getSecurityContext()</code>. The + * default implementation expects context to be an AccessControlContext, + * and it calls <code>AccessControlContext.checkPermission(perm)</code>. + * + * @param perm the <code>Permission</code> required + * @param context a security context + * @throws SecurityException if permission is denied, or if context is + * not an AccessControlContext + * @throws NullPointerException if perm is null + * @see #getSecurityContext() + * @see AccessControlContext#checkPermission(Permission) + * @since 1.2 + */ + public void checkPermission(Permission perm, Object context) + { + if (! (context instanceof AccessControlContext)) + throw new SecurityException("Missing context"); + ((AccessControlContext) context).checkPermission(perm); + } + + /** + * Check if the current thread is allowed to create a ClassLoader. This + * method is called from ClassLoader.ClassLoader(), and checks + * <code>RuntimePermission("createClassLoader")</code>. If you override + * this, you should call <code>super.checkCreateClassLoader()</code> rather + * than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see ClassLoader#ClassLoader() + */ + public void checkCreateClassLoader() + { + checkPermission(new RuntimePermission("createClassLoader")); + } + + /** + * Check if the current thread is allowed to modify another Thread. This is + * called by Thread.stop(), suspend(), resume(), interrupt(), destroy(), + * setPriority(), setName(), and setDaemon(). The default implementation + * checks <code>RuntimePermission("modifyThread")</code> on system threads + * (ie. threads in ThreadGroup with a null parent), and returns silently on + * other threads. + * + * <p>If you override this, you must do two things. First, call + * <code>super.checkAccess(t)</code>, to make sure you are not relaxing + * requirements. Second, if the calling thread has + * <code>RuntimePermission("modifyThread")</code>, return silently, so that + * core classes (the Classpath library!) can modify any thread. + * + * @param thread the other Thread to check + * @throws SecurityException if permission is denied + * @throws NullPointerException if thread is null + * @see Thread#stop() + * @see Thread#suspend() + * @see Thread#resume() + * @see Thread#setPriority(int) + * @see Thread#setName(String) + * @see Thread#setDaemon(boolean) + */ + public void checkAccess(Thread thread) + { + if (thread.getThreadGroup() != null + && thread.getThreadGroup().getParent() == null) + checkPermission(new RuntimePermission("modifyThread")); + } + + /** + * Check if the current thread is allowed to modify a ThreadGroup. This is + * called by Thread.Thread() (to add a thread to the ThreadGroup), + * ThreadGroup.ThreadGroup() (to add this ThreadGroup to a parent), + * ThreadGroup.stop(), suspend(), resume(), interrupt(), destroy(), + * setDaemon(), and setMaxPriority(). The default implementation + * checks <code>RuntimePermission("modifyThread")</code> on the system group + * (ie. the one with a null parent), and returns silently on other groups. + * + * <p>If you override this, you must do two things. First, call + * <code>super.checkAccess(t)</code>, to make sure you are not relaxing + * requirements. Second, if the calling thread has + * <code>RuntimePermission("modifyThreadGroup")</code>, return silently, + * so that core classes (the Classpath library!) can modify any thread. + * + * @param g the ThreadGroup to check + * @throws SecurityException if permission is denied + * @throws NullPointerException if g is null + * @see Thread#Thread() + * @see ThreadGroup#ThreadGroup(String) + * @see ThreadGroup#stop() + * @see ThreadGroup#suspend() + * @see ThreadGroup#resume() + * @see ThreadGroup#interrupt() + * @see ThreadGroup#setDaemon(boolean) + * @see ThreadGroup#setMaxPriority(int) + */ + public void checkAccess(ThreadGroup g) + { + if (g.getParent() == null) + checkPermission(new RuntimePermission("modifyThreadGroup")); + } + + /** + * Check if the current thread is allowed to exit the JVM with the given + * status. This method is called from Runtime.exit() and Runtime.halt(). + * The default implementation checks + * <code>RuntimePermission("exitVM")</code>. If you override this, call + * <code>super.checkExit</code> rather than throwing an exception. + * + * @param status the status to exit with + * @throws SecurityException if permission is denied + * @see Runtime#exit(int) + * @see Runtime#halt(int) + */ + public void checkExit(int status) + { + checkPermission(new RuntimePermission("exitVM")); + } + + /** + * Check if the current thread is allowed to execute the given program. This + * method is called from Runtime.exec(). If the name is an absolute path, + * the default implementation checks + * <code>FilePermission(program, "execute")</code>, otherwise it checks + * <code>FilePermission("<<ALL FILES>>", "execute")</code>. If + * you override this, call <code>super.checkExec</code> rather than + * throwing an exception. + * + * @param program the name of the program to exec + * @throws SecurityException if permission is denied + * @throws NullPointerException if program is null + * @see Runtime#exec(String[], String[], File) + */ + public void checkExec(String program) + { + if (! program.equals(new File(program).getAbsolutePath())) + program = "<<ALL FILES>>"; + checkPermission(new FilePermission(program, "execute")); + } + + /** + * Check if the current thread is allowed to link in the given native + * library. This method is called from Runtime.load() (and hence, by + * loadLibrary() as well). The default implementation checks + * <code>RuntimePermission("loadLibrary." + filename)</code>. If you + * override this, call <code>super.checkLink</code> rather than throwing + * an exception. + * + * @param filename the full name of the library to load + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see Runtime#load(String) + */ + public void checkLink(String filename) + { + // Use the toString() hack to do the null check. + checkPermission(new RuntimePermission("loadLibrary." + + filename.toString())); + } + + /** + * Check if the current thread is allowed to read the given file using the + * FileDescriptor. This method is called from + * FileInputStream.FileInputStream(). The default implementation checks + * <code>RuntimePermission("readFileDescriptor")</code>. If you override + * this, call <code>super.checkRead</code> rather than throwing an + * exception. + * + * @param desc the FileDescriptor representing the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if desc is null + * @see FileInputStream#FileInputStream(FileDescriptor) + */ + public void checkRead(FileDescriptor desc) + { + if (desc == null) + throw new NullPointerException(); + checkPermission(new RuntimePermission("readFileDescriptor")); + } + + /** + * Check if the current thread is allowed to read the given file. This + * method is called from FileInputStream.FileInputStream(), + * RandomAccessFile.RandomAccessFile(), File.exists(), canRead(), isFile(), + * isDirectory(), lastModified(), length() and list(). The default + * implementation checks <code>FilePermission(filename, "read")</code>. If + * you override this, call <code>super.checkRead</code> rather than + * throwing an exception. + * + * @param filename the full name of the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see File + * @see FileInputStream#FileInputStream(String) + * @see RandomAccessFile#RandomAccessFile(String, String) + */ + public void checkRead(String filename) + { + checkPermission(new FilePermission(filename, "read")); + } + + /** + * Check if the current thread is allowed to read the given file. using the + * given security context. The context must be a result of a previous call + * to <code>getSecurityContext()</code>. The default implementation checks + * <code>AccessControlContext.checkPermission(new FilePermission(filename, + * "read"))</code>. If you override this, call <code>super.checkRead</code> + * rather than throwing an exception. + * + * @param filename the full name of the file to access + * @param context the context to determine access for + * @throws SecurityException if permission is denied, or if context is + * not an AccessControlContext + * @throws NullPointerException if filename is null + * @see #getSecurityContext() + * @see AccessControlContext#checkPermission(Permission) + */ + public void checkRead(String filename, Object context) + { + if (! (context instanceof AccessControlContext)) + throw new SecurityException("Missing context"); + AccessControlContext ac = (AccessControlContext) context; + ac.checkPermission(new FilePermission(filename, "read")); + } + + /** + * Check if the current thread is allowed to write the given file using the + * FileDescriptor. This method is called from + * FileOutputStream.FileOutputStream(). The default implementation checks + * <code>RuntimePermission("writeFileDescriptor")</code>. If you override + * this, call <code>super.checkWrite</code> rather than throwing an + * exception. + * + * @param desc the FileDescriptor representing the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if desc is null + * @see FileOutputStream#FileOutputStream(FileDescriptor) + */ + public void checkWrite(FileDescriptor desc) + { + if (desc == null) + throw new NullPointerException(); + checkPermission(new RuntimePermission("writeFileDescriptor")); + } + + /** + * Check if the current thread is allowed to write the given file. This + * method is called from FileOutputStream.FileOutputStream(), + * RandomAccessFile.RandomAccessFile(), File.canWrite(), mkdir(), and + * renameTo(). The default implementation checks + * <code>FilePermission(filename, "write")</code>. If you override this, + * call <code>super.checkWrite</code> rather than throwing an exception. + * + * @param filename the full name of the file to access + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see File + * @see File#canWrite() + * @see File#mkdir() + * @see File#renameTo(File) + * @see FileOutputStream#FileOutputStream(String) + * @see RandomAccessFile#RandomAccessFile(String, String) + */ + public void checkWrite(String filename) + { + checkPermission(new FilePermission(filename, "write")); + } + + /** + * Check if the current thread is allowed to delete the given file. This + * method is called from File.delete(). The default implementation checks + * <code>FilePermission(filename, "delete")</code>. If you override this, + * call <code>super.checkDelete</code> rather than throwing an exception. + * + * @param filename the full name of the file to delete + * @throws SecurityException if permission is denied + * @throws NullPointerException if filename is null + * @see File#delete() + */ + public void checkDelete(String filename) + { + checkPermission(new FilePermission(filename, "delete")); + } + + /** + * Check if the current thread is allowed to connect to a given host on a + * given port. This method is called from Socket.Socket(). A port number + * of -1 indicates the caller is attempting to determine an IP address, so + * the default implementation checks + * <code>SocketPermission(host, "resolve")</code>. Otherwise, the default + * implementation checks + * <code>SocketPermission(host + ":" + port, "connect")</code>. If you + * override this, call <code>super.checkConnect</code> rather than throwing + * an exception. + * + * @param host the host to connect to + * @param port the port to connect on + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @see Socket#Socket() + */ + public void checkConnect(String host, int port) + { + if (port == -1) + checkPermission(new SocketPermission(host, "resolve")); + else + // Use the toString() hack to do the null check. + checkPermission(new SocketPermission(host.toString() + ":" + port, + "connect")); + } + + /** + * Check if the current thread is allowed to connect to a given host on a + * given port, using the given security context. The context must be a + * result of a previous call to <code>getSecurityContext</code>. A port + * number of -1 indicates the caller is attempting to determine an IP + * address, so the default implementation checks + * <code>AccessControlContext.checkPermission(new SocketPermission(host, + * "resolve"))</code>. Otherwise, the default implementation checks + * <code>AccessControlContext.checkPermission(new SocketPermission(host + * + ":" + port, "connect"))</code>. If you override this, call + * <code>super.checkConnect</code> rather than throwing an exception. + * + * @param host the host to connect to + * @param port the port to connect on + * @param context the context to determine access for + * + * @throws SecurityException if permission is denied, or if context is + * not an AccessControlContext + * @throws NullPointerException if host is null + * + * @see #getSecurityContext() + * @see AccessControlContext#checkPermission(Permission) + */ + public void checkConnect(String host, int port, Object context) + { + if (! (context instanceof AccessControlContext)) + throw new SecurityException("Missing context"); + AccessControlContext ac = (AccessControlContext) context; + if (port == -1) + ac.checkPermission(new SocketPermission(host, "resolve")); + else + // Use the toString() hack to do the null check. + ac.checkPermission(new SocketPermission(host.toString() + ":" + port, + "connect")); + } + + /** + * Check if the current thread is allowed to listen to a specific port for + * data. This method is called by ServerSocket.ServerSocket(). The default + * implementation checks + * <code>SocketPermission("localhost:" + (port == 0 ? "1024-" : "" + port), + * "listen")</code>. If you override this, call + * <code>super.checkListen</code> rather than throwing an exception. + * + * @param port the port to listen on + * @throws SecurityException if permission is denied + * @see ServerSocket#ServerSocket(int) + */ + public void checkListen(int port) + { + checkPermission(new SocketPermission("localhost:" + + (port == 0 ? "1024-" : "" +port), + "listen")); + } + + /** + * Check if the current thread is allowed to accept a connection from a + * particular host on a particular port. This method is called by + * ServerSocket.implAccept(). The default implementation checks + * <code>SocketPermission(host + ":" + port, "accept")</code>. If you + * override this, call <code>super.checkAccept</code> rather than throwing + * an exception. + * + * @param host the host which wishes to connect + * @param port the port the connection will be on + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @see ServerSocket#accept() + */ + public void checkAccept(String host, int port) + { + // Use the toString() hack to do the null check. + checkPermission(new SocketPermission(host.toString() + ":" + port, + "accept")); + } + + /** + * Check if the current thread is allowed to read and write multicast to + * a particular address. The default implementation checks + * <code>SocketPermission(addr.getHostAddress(), "accept,connect")</code>. + * If you override this, call <code>super.checkMulticast</code> rather than + * throwing an exception. + * + * @param addr the address to multicast to + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @since 1.1 + */ + public void checkMulticast(InetAddress addr) + { + checkPermission(new SocketPermission(addr.getHostAddress(), + "accept,connect")); + } + + /** + *Check if the current thread is allowed to read and write multicast to + * a particular address with a particular ttl (time-to-live) value. The + * default implementation ignores ttl, and checks + * <code>SocketPermission(addr.getHostAddress(), "accept,connect")</code>. + * If you override this, call <code>super.checkMulticast</code> rather than + * throwing an exception. + * + * @param addr the address to multicast to + * @param ttl value in use for multicast send + * @throws SecurityException if permission is denied + * @throws NullPointerException if host is null + * @since 1.1 + * @deprecated use {@link #checkPermission(Permission)} instead + */ + public void checkMulticast(InetAddress addr, byte ttl) + { + checkPermission(new SocketPermission(addr.getHostAddress(), + "accept,connect")); + } + + /** + * Check if the current thread is allowed to read or write all the system + * properties at once. This method is called by System.getProperties() + * and setProperties(). The default implementation checks + * <code>PropertyPermission("*", "read,write")</code>. If you override + * this, call <code>super.checkPropertiesAccess</code> rather than + * throwing an exception. + * + * @throws SecurityException if permission is denied + * @see System#getProperties() + * @see System#setProperties(Properties) + */ + public void checkPropertiesAccess() + { + checkPermission(new PropertyPermission("*", "read,write")); + } + + /** + * Check if the current thread is allowed to read a particular system + * property (writes are checked directly via checkPermission). This method + * is called by System.getProperty() and setProperty(). The default + * implementation checks <code>PropertyPermission(key, "read")</code>. If + * you override this, call <code>super.checkPropertyAccess</code> rather + * than throwing an exception. + * + * @param key the key of the property to check + * + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + * + * @see System#getProperty(String) + */ + public void checkPropertyAccess(String key) + { + checkPermission(new PropertyPermission(key, "read")); + } + + /** + * Check if the current thread is allowed to create a top-level window. If + * it is not, the operation should still go through, but some sort of + * nonremovable warning should be placed on the window to show that it + * is untrusted. This method is called by Window.Window(). The default + * implementation checks + * <code>AWTPermission("showWindowWithoutWarningBanner")</code>, and returns + * true if no exception was thrown. If you override this, use + * <code>return super.checkTopLevelWindow</code> rather than returning + * false. + * + * @param window the window to create + * @return true if there is permission to show the window without warning + * @throws NullPointerException if window is null + * @see java.awt.Window#Window(java.awt.Frame) + */ + public boolean checkTopLevelWindow(Object window) + { + if (window == null) + throw new NullPointerException(); + try + { + checkPermission(new AWTPermission("showWindowWithoutWarningBanner")); + return true; + } + catch (SecurityException e) + { + return false; + } + } + + /** + * Check if the current thread is allowed to create a print job. This + * method is called by Toolkit.getPrintJob(). The default implementation + * checks <code>RuntimePermission("queuePrintJob")</code>. If you override + * this, call <code>super.checkPrintJobAccess</code> rather than throwing + * an exception. + * + * @throws SecurityException if permission is denied + * @see java.awt.Toolkit#getPrintJob(java.awt.Frame, String, Properties) + * @since 1.1 + */ + public void checkPrintJobAccess() + { + checkPermission(new RuntimePermission("queuePrintJob")); + } + + /** + * Check if the current thread is allowed to use the system clipboard. This + * method is called by Toolkit.getSystemClipboard(). The default + * implementation checks <code>AWTPermission("accessClipboard")</code>. If + * you override this, call <code>super.checkSystemClipboardAccess</code> + * rather than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see java.awt.Toolkit#getSystemClipboard() + * @since 1.1 + */ + public void checkSystemClipboardAccess() + { + checkPermission(new AWTPermission("accessClipboard")); + } + + /** + * Check if the current thread is allowed to use the AWT event queue. This + * method is called by Toolkit.getSystemEventQueue(). The default + * implementation checks <code>AWTPermission("accessEventQueue")</code>. + * you override this, call <code>super.checkAwtEventQueueAccess</code> + * rather than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see java.awt.Toolkit#getSystemEventQueue() + * @since 1.1 + */ + public void checkAwtEventQueueAccess() + { + checkPermission(new AWTPermission("accessEventQueue")); + } + + /** + * Check if the current thread is allowed to access the specified package + * at all. This method is called by ClassLoader.loadClass() in user-created + * ClassLoaders. The default implementation gets a list of all restricted + * packages, via <code>Security.getProperty("package.access")</code>. Then, + * if packageName starts with or equals any restricted package, it checks + * <code>RuntimePermission("accessClassInPackage." + packageName)</code>. + * If you override this, you should call + * <code>super.checkPackageAccess</code> before doing anything else. + * + * @param packageName the package name to check access to + * @throws SecurityException if permission is denied + * @throws NullPointerException if packageName is null + * @see ClassLoader#loadClass(String, boolean) + * @see Security#getProperty(String) + */ + public void checkPackageAccess(String packageName) + { + checkPackageList(packageName, "package.access", "accessClassInPackage."); + } + + /** + * Check if the current thread is allowed to define a class into the + * specified package. This method is called by ClassLoader.loadClass() in + * user-created ClassLoaders. The default implementation gets a list of all + * restricted packages, via + * <code>Security.getProperty("package.definition")</code>. Then, if + * packageName starts with or equals any restricted package, it checks + * <code>RuntimePermission("defineClassInPackage." + packageName)</code>. + * If you override this, you should call + * <code>super.checkPackageDefinition</code> before doing anything else. + * + * @param packageName the package name to check access to + * @throws SecurityException if permission is denied + * @throws NullPointerException if packageName is null + * @see ClassLoader#loadClass(String, boolean) + * @see Security#getProperty(String) + */ + public void checkPackageDefinition(String packageName) + { + checkPackageList(packageName, "package.definition", "defineClassInPackage."); + } + + /** + * Check if the current thread is allowed to set the current socket factory. + * This method is called by Socket.setSocketImplFactory(), + * ServerSocket.setSocketFactory(), and URL.setURLStreamHandlerFactory(). + * The default implementation checks + * <code>RuntimePermission("setFactory")</code>. If you override this, call + * <code>super.checkSetFactory</code> rather than throwing an exception. + * + * @throws SecurityException if permission is denied + * @see Socket#setSocketImplFactory(SocketImplFactory) + * @see ServerSocket#setSocketFactory(SocketImplFactory) + * @see URL#setURLStreamHandlerFactory(URLStreamHandlerFactory) + */ + public void checkSetFactory() + { + checkPermission(new RuntimePermission("setFactory")); + } + + /** + * Check if the current thread is allowed to get certain types of Methods, + * Fields and Constructors from a Class object. This method is called by + * Class.getMethod[s](), Class.getField[s](), Class.getConstructor[s], + * Class.getDeclaredMethod[s](), Class.getDeclaredField[s](), and + * Class.getDeclaredConstructor[s](). The default implementation allows + * PUBLIC access, and access to classes defined by the same classloader as + * the code performing the reflection. Otherwise, it checks + * <code>RuntimePermission("accessDeclaredMembers")</code>. If you override + * this, do not call <code>super.checkMemberAccess</code>, as this would + * mess up the stack depth check that determines the ClassLoader requesting + * the access. + * + * @param c the Class to check + * @param memberType either DECLARED or PUBLIC + * @throws SecurityException if permission is denied, including when + * memberType is not DECLARED or PUBLIC + * @throws NullPointerException if c is null + * @see Class + * @see Member#DECLARED + * @see Member#PUBLIC + * @since 1.1 + */ + public void checkMemberAccess(Class c, int memberType) + { + if (c == null) + throw new NullPointerException(); + if (memberType == Member.PUBLIC) + return; + // XXX Allow access to classes created by same classloader before next + // check. + checkPermission(new RuntimePermission("accessDeclaredMembers")); + } + + /** + * Test whether a particular security action may be taken. The default + * implementation checks <code>SecurityPermission(action)</code>. If you + * override this, call <code>super.checkSecurityAccess</code> rather than + * throwing an exception. + * + * @param action the desired action to take + * @throws SecurityException if permission is denied + * @throws NullPointerException if action is null + * @throws IllegalArgumentException if action is "" + * @since 1.1 + */ + public void checkSecurityAccess(String action) + { + checkPermission(new SecurityPermission(action)); + } + + /** + * Get the ThreadGroup that a new Thread should belong to by default. Called + * by Thread.Thread(). The default implementation returns the current + * ThreadGroup of the current Thread. <STRONG>Spec Note:</STRONG> it is not + * clear whether the new Thread is guaranteed to pass the + * checkAccessThreadGroup() test when using this ThreadGroup, but I presume + * so. + * + * @return the ThreadGroup to put the new Thread into + * @since 1.1 + */ + public ThreadGroup getThreadGroup() + { + return Thread.currentThread().getThreadGroup(); + } + + /** + * Helper that checks a comma-separated list of restricted packages, from + * <code>Security.getProperty("package.definition")</code>, for the given + * package access permission. If packageName starts with or equals any + * restricted package, it checks + * <code>RuntimePermission(permission + packageName)</code>. + * + * @param packageName the package name to check access to + * @param restriction "package.access" or "package.definition" + * @param permission the base permission, including the '.' + * @throws SecurityException if permission is denied + * @throws NullPointerException if packageName is null + * @see #checkPackageAccess(String) + * @see #checkPackageDefinition(String) + */ + void checkPackageList(String packageName, final String restriction, + String permission) + { + if (packageName == null) + throw new NullPointerException(); + + String list = (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return Security.getProperty(restriction); + } + }); + + if (list == null || list.equals("")) + return; + + String packageNamePlusDot = packageName + "."; + + StringTokenizer st = new StringTokenizer(list, ","); + while (st.hasMoreTokens()) + { + if (packageNamePlusDot.startsWith(st.nextToken())) + { + Permission p = new RuntimePermission(permission + packageName); + checkPermission(p); + return; + } + } + } +} diff --git a/gcc-4.2.1/libjava/java/lang/String.java b/gcc-4.2.1/libjava/java/lang/String.java new file mode 100644 index 000000000..bd75797a2 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/String.java @@ -0,0 +1,1397 @@ +/* String.java -- immutable character sequences; the object of string literals + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import java.io.Serializable; +import java.io.UnsupportedEncodingException; +import java.lang.Comparable; +import java.util.Comparator; +import java.util.Locale; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +/** + * Strings represent an immutable set of characters. All String literals + * are instances of this class, and two string literals with the same contents + * refer to the same String object. + * + * <p>This class also includes a number of methods for manipulating the + * contents of strings (of course, creating a new object if there are any + * changes, as String is immutable). Case mapping relies on Unicode 3.0.0 + * standards, where some character sequences have a different number of + * characters in the uppercase version than the lower case. + * + * <p>Strings are special, in that they are the only object with an overloaded + * operator. When you use '+' with at least one String argument, both + * arguments have String conversion performed on them, and another String (not + * guaranteed to be unique) results. + * + * <p>String is special-cased when doing data serialization - rather than + * listing the fields of this class, a String object is converted to a string + * literal in the object stream. + * + * @author Paul N. Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Per Bothner (bothner@cygnus.com) + * @since 1.0 + * @status updated to 1.4 + */ +public final class String implements Serializable, Comparable, CharSequence +{ + // WARNING: String is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * This is probably not necessary because this class is special cased already + * but it will avoid showing up as a discrepancy when comparing SUIDs. + */ + private static final long serialVersionUID = -6849794470754667710L; + + /** + * This is the object that holds the characters that make up the + * String. It might be a char[], or it could be String. It could + * even be `this'. The actual characters can't be located using + * pure Java code. + * @see #boffset + */ + private Object data; + + /** + * This is a <emph>byte</emph> offset of the actual characters from + * the start of the character-holding object. Don't use this field + * in Java code. + */ + private int boffset; + + /** + * Holds the number of characters in value. Package visible for use + * by trusted code. + */ + int count; + + /** + * Caches the result of hashCode(). If this value is zero, the hashcode + * is considered uncached (even if 0 is the correct hash value). + */ + private int cachedHashCode; + + /** + * An implementation for {@link CASE_INSENSITIVE_ORDER}. + * This must be {@link Serializable}. The class name is dictated by + * compatibility with Sun's JDK. + */ + private static final class CaseInsensitiveComparator + implements Comparator, Serializable + { + /** + * Compatible with JDK 1.2. + */ + private static final long serialVersionUID = 8575799808933029326L; + + /** + * The default private constructor generates unnecessary overhead. + */ + CaseInsensitiveComparator() {} + + /** + * Compares to Strings, using + * <code>String.compareToIgnoreCase(String)</code>. + * + * @param o1 the first string + * @param o2 the second string + * @return < 0, 0, or > 0 depending on the case-insensitive + * comparison of the two strings. + * @throws NullPointerException if either argument is null + * @throws ClassCastException if either argument is not a String + * @see #compareToIgnoreCase(String) + */ + public int compare(Object o1, Object o2) + { + return ((String) o1).compareToIgnoreCase((String) o2); + } + } // class CaseInsensitiveComparator + + /** + * A Comparator that uses <code>String.compareToIgnoreCase(String)</code>. + * This comparator is {@link Serializable}. Note that it ignores Locale, + * for that, you want a Collator. + * + * @see Collator#compare(String, String) + * @since 1.2 + */ + public static final Comparator CASE_INSENSITIVE_ORDER + = new CaseInsensitiveComparator(); + + /** + * Creates an empty String (length 0). Unless you really need a new object, + * consider using <code>""</code> instead. + */ + public String() + { + data = "".data; + boffset = 0; + count = 0; + } + + /** + * Copies the contents of a String to a new String. Since Strings are + * immutable, only a shallow copy is performed. + * + * @param str String to copy + * @throws NullPointerException if value is null + */ + public String(String str) + { + data = str.data; + boffset = str.boffset; + count = str.count; + cachedHashCode = str.cachedHashCode; + } + + /** + * Creates a new String using the character sequence of the char array. + * Subsequent changes to data do not affect the String. + * + * @param data char array to copy + * @throws NullPointerException if data is null + */ + public String(char[] data) + { + init(data, 0, data.length, false); + } + + /** + * Creates a new String using the character sequence of a subarray of + * characters. The string starts at offset, and copies count chars. + * Subsequent changes to data do not affect the String. + * + * @param data char array to copy + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public String(char[] data, int offset, int count) + { + init(data, offset, count, false); + } + + /** + * Creates a new String using an 8-bit array of integer values, starting at + * an offset, and copying up to the count. Each character c, using + * corresponding byte b, is created in the new String as if by performing: + * + * <pre> + * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) + * </pre> + * + * @param ascii array of integer values + * @param hibyte top byte of each Unicode character + * @param offset position (base 0) to start copying out of ascii + * @param count the number of characters from ascii to copy + * @throws NullPointerException if ascii is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > ascii.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(byte[]) + * @see #String(byte[], String) + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @deprecated use {@link #String(byte[], int, int, String)} to perform + * correct encoding + */ + public String(byte[] ascii, int hibyte, int offset, int count) + { + init(ascii, hibyte, offset, count); + } + + /** + * Creates a new String using an 8-bit array of integer values. Each + * character c, using corresponding byte b, is created in the new String + * as if by performing: + * + * <pre> + * c = (char) (((hibyte & 0xff) << 8) | (b & 0xff)) + * </pre> + * + * @param ascii array of integer values + * @param hibyte top byte of each Unicode character + * @throws NullPointerException if ascii is null + * @see #String(byte[]) + * @see #String(byte[], String) + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @see #String(byte[], int, int, int) + * @deprecated use {@link #String(byte[], String)} to perform + * correct encoding + */ + public String(byte[] ascii, int hibyte) + { + init(ascii, hibyte, 0, ascii.length); + } + + /** + * Creates a new String using the portion of the byte array starting at the + * offset and ending at offset + count. Uses the specified encoding type + * to decode the byte array, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param offset the offset to start at + * @param count the number of characters in the array to use + * @param encoding the name of the encoding to use + * @throws NullPointerException if data or encoding is null + * @throws IndexOutOfBoundsException if offset or count is incorrect + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @throws UnsupportedEncodingException if encoding is not found + * @throws Error if the decoding fails + * @since 1.1 + */ + public String(byte[] data, int offset, int count, String encoding) + throws UnsupportedEncodingException + { + init (data, offset, count, encoding); + } + + /** + * Creates a new String using the byte array. Uses the specified encoding + * type to decode the byte array, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param encoding the name of the encoding to use + * @throws NullPointerException if data or encoding is null + * @throws UnsupportedEncodingException if encoding is not found + * @throws Error if the decoding fails + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data, String encoding) + throws UnsupportedEncodingException + { + this(data, 0, data.length, encoding); + } + + /** + * Creates a new String using the portion of the byte array starting at the + * offset and ending at offset + count. Uses the encoding of the platform's + * default charset, so the resulting string may be longer or shorter than + * the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified + * if the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @param offset the offset to start at + * @param count the number of characters in the array to use + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if offset or count is incorrect + * @throws Error if the decoding fails + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data, int offset, int count) + { + try + { + init (data, offset, count, + System.getProperty("file.encoding", "8859_1")); + } + catch (UnsupportedEncodingException x1) + { + // Maybe the default encoding is bad. + try + { + init (data, offset, count, "8859_1"); + } + catch (UnsupportedEncodingException x2) + { + // We know this can't happen. + } + } + } + + /** + * Creates a new String using the byte array. Uses the encoding of the + * platform's default charset, so the resulting string may be longer or + * shorter than the byte array. For more decoding control, use + * {@link java.nio.charset.CharsetDecoder}. The behavior is not specified + * if the decoder encounters invalid characters; this implementation throws + * an Error. + * + * @param data byte array to copy + * @throws NullPointerException if data is null + * @throws Error if the decoding fails + * @see #String(byte[], int, int) + * @see #String(byte[], int, int, String) + * @since 1.1 + */ + public String(byte[] data) + { + this(data, 0, data.length); + } + + /** + * Creates a new String using the character sequence represented by + * the StringBuffer. Subsequent changes to buf do not affect the String. + * + * @param buffer StringBuffer to copy + * @throws NullPointerException if buffer is null + */ + public String(StringBuffer buffer) + { + synchronized (buffer) + { + // Share unless buffer is 3/4 empty. + boolean should_copy = ((buffer.count << 2) < buffer.value.length); + if (! should_copy) + buffer.shared = true; + init (buffer.value, 0, buffer.count, ! should_copy); + } + } + + /** + * Creates a new String using the character sequence represented by + * the StringBuilder. Subsequent changes to buf do not affect the String. + * + * @param buffer StringBuilder to copy + * @throws NullPointerException if buffer is null + */ + public String(StringBuilder buffer) + { + this(buffer.value, 0, buffer.count); + } + + /** + * Special constructor which can share an array when safe to do so. + * + * @param data the characters to copy + * @param offset the location to start from + * @param count the number of characters to use + * @param dont_copy true if the array is trusted, and need not be copied + * @throws NullPointerException if chars is null + * @throws StringIndexOutOfBoundsException if bounds check fails + */ + String(char[] data, int offset, int count, boolean dont_copy) + { + init(data, offset, count, dont_copy); + } + + // This is used by gnu.gcj.runtime.StringBuffer, so it must have + // package-private protection. It is accessed via CNI and so avoids + // ordinary protection mechanisms. + String(gnu.gcj.runtime.StringBuffer buffer) + { + // No need to synchronize or mark the buffer, since we know it is + // only used once. + init (buffer); + } + + /** + * Returns the number of characters contained in this String. + * + * @return the length of this String + */ + public int length() + { + return count; + } + + /** + * Returns the character located at the specified index within this String. + * + * @param index position of character to return (base 0) + * @return character located at position index + * @throws IndexOutOfBoundsException if index < 0 || index >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public native char charAt(int index); + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public synchronized int codePointAt(int index) + { + // Use the CharSequence overload as we get better range checking + // this way. + return Character.codePointAt(this, index); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at <code>index-1</code> and + * <code>index-2</code> to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @since 1.5 + */ + public synchronized int codePointBefore(int index) + { + // Use the CharSequence overload as we get better range checking + // this way. + return Character.codePointBefore(this, index); + } + + /** + * Copies characters from this String starting at a specified start index, + * ending at a specified stop index, to a character array starting at + * a specified destination begin index. + * + * @param srcBegin index to begin copying characters from this String + * @param srcEnd index after the last character to be copied from this String + * @param dst character array which this String is copied into + * @param dstBegin index to start writing characters into dst + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any indices are out of bounds + * (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dst problems cause an + * ArrayIndexOutOfBoundsException) + */ + public native void getChars(int srcBegin, int srcEnd, + char[] dst, int dstBegin); + + /** + * Copies the low byte of each character from this String starting at a + * specified start index, ending at a specified stop index, to a byte array + * starting at a specified destination begin index. + * + * @param srcBegin index to being copying characters from this String + * @param srcEnd index after the last character to be copied from this String + * @param dst byte array which each low byte of this String is copied into + * @param dstBegin index to start writing characters into dst + * @throws NullPointerException if dst is null and copy length is non-zero + * @throws IndexOutOfBoundsException if any indices are out of bounds + * (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dst problems cause an + * ArrayIndexOutOfBoundsException) + * @see #getBytes() + * @see #getBytes(String) + * @deprecated use {@link #getBytes()}, which uses a char to byte encoder + */ + public native void getBytes(int srcBegin, int srcEnd, + byte[] dst, int dstBegin); + + /** + * Converts the Unicode characters in this String to a byte array. Uses the + * specified encoding method, so the result may be longer or shorter than + * the String. For more encoding control, use + * {@link java.nio.charset.CharsetEncoder}, and for valid character sets, + * see {@link java.nio.charset.Charset}. The behavior is not specified if + * the encoder encounters a problem; this implementation returns null. + * + * @param enc encoding name + * @return the resulting byte array, or null on a problem + * @throws NullPointerException if enc is null + * @throws UnsupportedEncodingException if encoding is not supported + * @since 1.1 + */ + public native byte[] getBytes(String enc) + throws UnsupportedEncodingException; + + /** + * Converts the Unicode characters in this String to a byte array. Uses the + * encoding of the platform's default charset, so the result may be longer + * or shorter than the String. For more encoding control, use + * {@link java.nio.charset.CharsetEncoder}. The behavior is not specified if + * the encoder encounters a problem; this implementation returns null. + * + * @return the resulting byte array, or null on a problem + * @since 1.1 + */ + public byte[] getBytes() + { + try + { + return getBytes (System.getProperty("file.encoding", "8859_1")); + } + catch (UnsupportedEncodingException x) + { + // This probably shouldn't happen, but could if file.encoding + // is somehow changed to a value we don't understand. + try + { + return getBytes ("8859_1"); + } + catch (UnsupportedEncodingException x2) + { + // This really shouldn't happen, because the 8859_1 + // encoding should always be available. + throw new InternalError ("couldn't find 8859_1 encoder"); + } + } + } + + /** + * Predicate which compares anObject to this. This is true only for Strings + * with the same character sequence. + * + * @param anObject the object to compare + * @return true if anObject is semantically equal to this + * @see #compareTo(String) + * @see #equalsIgnoreCase(String) + */ + public native boolean equals(Object anObject); + + /** + * Compares the given StringBuffer to this String. This is true if the + * StringBuffer has the same content as this String at this moment. + * + * @param buffer the StringBuffer to compare to + * @return true if StringBuffer has the same character sequence + * @throws NullPointerException if the given StringBuffer is null + * @since 1.4 + */ + public native boolean contentEquals(StringBuffer buffer); + + /** + * Compares the given CharSequence to this String. This is true if + * the CharSequence has the same content as this String at this + * moment. + * + * @param seq the CharSequence to compare to + * @return true if CharSequence has the same character sequence + * @throws NullPointerException if the given CharSequence is null + * @since 1.5 + */ + public native boolean contentEquals(CharSequence seq); + + /** + * Compares a String to this String, ignoring case. This does not handle + * multi-character capitalization exceptions; instead the comparison is + * made on a character-by-character basis, and is true if:<br><ul> + * <li><code>c1 == c2</code></li> + * <li><code>Character.toUpperCase(c1) + * == Character.toUpperCase(c2)</code></li> + * <li><code>Character.toLowerCase(c1) + * == Character.toLowerCase(c2)</code></li> + * </ul> + * + * @param anotherString String to compare to this String + * @return true if anotherString is equal, ignoring case + * @see #equals(Object) + * @see Character#toUpperCase(char) + * @see Character#toLowerCase(char) + */ + public native boolean equalsIgnoreCase(String anotherString); + + /** + * Compares this String and another String (case sensitive, + * lexicographically). The result is less than 0 if this string sorts + * before the other, 0 if they are equal, and greater than 0 otherwise. + * After any common starting sequence is skipped, the result is + * <code>this.charAt(k) - anotherString.charAt(k)</code> if both strings + * have characters remaining, or + * <code>this.length() - anotherString.length()</code> if one string is + * a subsequence of the other. + * + * @param anotherString the String to compare against + * @return the comparison + * @throws NullPointerException if anotherString is null + */ + public native int compareTo(String anotherString); + + /** + * Behaves like <code>compareTo(java.lang.String)</code> unless the Object + * is not a <code>String</code>. Then it throws a + * <code>ClassCastException</code>. + * + * @param o the object to compare against + * @return the comparison + * @throws NullPointerException if o is null + * @throws ClassCastException if o is not a <code>String</code> + * @since 1.2 + */ + public int compareTo(Object o) + { + return compareTo((String) o); + } + + /** + * Compares this String and another String (case insensitive). This + * comparison is <em>similar</em> to equalsIgnoreCase, in that it ignores + * locale and multi-characater capitalization, and compares characters + * after performing + * <code>Character.toLowerCase(Character.toUpperCase(c))</code> on each + * character of the string. This is unsatisfactory for locale-based + * comparison, in which case you should use {@link java.text.Collator}. + * + * @param str the string to compare against + * @return the comparison + * @see Collator#compare(String, String) + * @since 1.2 + */ + public int compareToIgnoreCase(String str) + { + return this.toUpperCase().toLowerCase().compareTo( + str.toUpperCase().toLowerCase()); + } + + /** + * Predicate which determines if this String matches another String + * starting at a specified offset for each String and continuing + * for a specified length. Indices out of bounds are harmless, and give + * a false result. + * + * @param toffset index to start comparison at for this String + * @param other String to compare region to this String + * @param ooffset index to start comparison at for other + * @param len number of characters to compare + * @return true if regions match (case sensitive) + * @throws NullPointerException if other is null + */ + public native boolean regionMatches(int toffset, + String other, int ooffset, int len); + + /** + * Predicate which determines if this String matches another String + * starting at a specified offset for each String and continuing + * for a specified length, optionally ignoring case. Indices out of bounds + * are harmless, and give a false result. Case comparisons are based on + * <code>Character.toLowerCase()</code> and + * <code>Character.toUpperCase()</code>, not on multi-character + * capitalization expansions. + * + * @param ignoreCase true if case should be ignored in comparision + * @param toffset index to start comparison at for this String + * @param other String to compare region to this String + * @param oofset index to start comparison at for other + * @param len number of characters to compare + * @return true if regions match, false otherwise + * @throws NullPointerException if other is null + */ + public native boolean regionMatches(boolean ignoreCase, int toffset, + String other, int ooffset, int len); + + /** + * Predicate which determines if this String contains the given prefix, + * beginning comparison at toffset. The result is false if toffset is + * negative or greater than this.length(), otherwise it is the same as + * <code>this.substring(toffset).startsWith(prefix)</code>. + * + * @param prefix String to compare + * @param toffset offset for this String where comparison starts + * @return true if this String starts with prefix + * @throws NullPointerException if prefix is null + * @see #regionMatches(boolean, int, String, int, int) + */ + public native boolean startsWith(String prefix, int toffset); + + /** + * Predicate which determines if this String starts with a given prefix. + * If the prefix is an empty String, true is returned. + * + * @param prefix String to compare + * @return true if this String starts with the prefix + * @throws NullPointerException if prefix is null + * @see #startsWith(String, int) + */ + public boolean startsWith(String prefix) + { + return startsWith (prefix, 0); + } + + /** + * Predicate which determines if this String ends with a given suffix. + * If the suffix is an empty String, true is returned. + * + * @param suffix String to compare + * @return true if this String ends with the suffix + * @throws NullPointerException if suffix is null + * @see #regionMatches(boolean, int, String, int, int) + */ + public boolean endsWith(String suffix) + { + return regionMatches (this.count - suffix.count, suffix, 0, suffix.count); + } + + /** + * Computes the hashcode for this String. This is done with int arithmetic, + * where ** represents exponentiation, by this formula:<br> + * <code>s[0]*31**(n-1) + s[1]*31**(n-2) + ... + s[n-1]</code>. + * + * @return hashcode value of this String + */ + public native int hashCode(); + + /** + * Finds the first instance of a character in this String. + * + * @param ch character to find + * @return location (base 0) of the character, or -1 if not found + */ + public int indexOf(int ch) + { + return indexOf(ch, 0); + } + + /** + * Finds the first instance of a character in this String, starting at + * a given index. If starting index is less than 0, the search + * starts at the beginning of this String. If the starting index + * is greater than the length of this String, -1 is returned. + * + * @param ch character to find + * @param fromIndex index to start the search + * @return location (base 0) of the character, or -1 if not found + */ + public native int indexOf(int ch, int fromIndex); + + /** + * Finds the last instance of a character in this String. + * + * @param ch character to find + * @return location (base 0) of the character, or -1 if not found + */ + public int lastIndexOf(int ch) + { + return lastIndexOf(ch, count - 1); + } + + /** + * Finds the last instance of a character in this String, starting at + * a given index. If starting index is greater than the maximum valid + * index, then the search begins at the end of this String. If the + * starting index is less than zero, -1 is returned. + * + * @param ch character to find + * @param fromIndex index to start the search + * @return location (base 0) of the character, or -1 if not found + */ + public native int lastIndexOf(int ch, int fromIndex); + + /** + * Finds the first instance of a String in this String. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this String, starting at + * a given index. If starting index is less than 0, the search + * starts at the beginning of this String. If the starting index + * is greater than the length of this String, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public native int indexOf(String str, int fromIndex); + + /** + * Finds the last instance of a String in this String. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this String, starting at + * a given index. If starting index is greater than the maximum valid + * index, then the search begins at the end of this String. If the + * starting index is less than zero, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int lastIndexOf(String str, int fromIndex) + { + if (fromIndex >= count) + fromIndex = count - str.count; + for (;; --fromIndex) + { + if (fromIndex < 0) + return -1; + if (startsWith(str, fromIndex)) + return fromIndex; + } + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at the end of this String. + * + * @param begin index to start substring (base 0) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || begin > length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public String substring(int begin) + { + return substring(begin, count); + } + + /** + * Creates a substring of this String, starting at a specified index + * and ending at one character before a specified index. + * + * @param begin index to start substring (inclusive, base 0) + * @param end index to end at (exclusive) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || end > length() + * || begin > end (while unspecified, this is a + * StringIndexOutOfBoundsException) + */ + public native String substring(int begin, int end); + + /** + * Creates a substring of this String, starting at a specified index + * and ending at one character before a specified index. This behaves like + * <code>substring(begin, end)</code>. + * + * @param begin index to start substring (inclusive, base 0) + * @param end index to end at (exclusive) + * @return new String which is a substring of this String + * @throws IndexOutOfBoundsException if begin < 0 || end > length() + * || begin > end + * @since 1.4 + */ + public CharSequence subSequence(int begin, int end) + { + return substring(begin, end); + } + + /** + * Concatenates a String to this String. This results in a new string unless + * one of the two originals is "". + * + * @param str String to append to this String + * @return newly concatenated String + * @throws NullPointerException if str is null + */ + public native String concat(String str); + + /** + * Replaces every instance of a character in this String with a new + * character. If no replacements occur, this is returned. + * + * @param oldChar the old character to replace + * @param newChar the new character + * @return new String with all instances of oldChar replaced with newChar + */ + public native String replace(char oldChar, char newChar); + + /** + * Test if this String matches a regular expression. This is shorthand for + * <code>{@link Pattern}.matches(regex, this)</code>. + * + * @param regex the pattern to match + * @return true if the pattern matches + * @throws NullPointerException if regex is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#matches(String, CharSequence) + * @since 1.4 + */ + public boolean matches(String regex) + { + return Pattern.matches(regex, this); + } + + /** + * Replaces the first substring match of the regular expression with a + * given replacement. This is shorthand for <code>{@link Pattern} + * .compile(regex).matcher(this).replaceFirst(replacement)</code>. + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceAll(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceFirst(String) + * @since 1.4 + */ + public String replaceFirst(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceFirst(replacement); + } + + /** + * Replaces all matching substrings of the regular expression with a + * given replacement. This is shorthand for <code>{@link Pattern} + * .compile(regex).matcher(this).replaceAll(replacement)</code>. + * + * @param regex the pattern to match + * @param replacement the replacement string + * @return the modified string + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #replaceFirst(String, String) + * @see Pattern#compile(String) + * @see Pattern#matcher(CharSequence) + * @see Matcher#replaceAll(String) + * @since 1.4 + */ + public String replaceAll(String regex, String replacement) + { + return Pattern.compile(regex).matcher(this).replaceAll(replacement); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * + * <p>The limit affects the length of the array. If it is positive, the + * array will contain at most n elements (n - 1 pattern matches). If + * negative, the array length is unlimited, but there can be trailing empty + * entries. if 0, the array length is unlimited, and trailing empty entries + * are discarded. + * + * <p>For example, splitting "boo:and:foo" yields:<br> + * <table border=0> + * <th><td>Regex</td> <td>Limit</td> <td>Result</td></th> + * <tr><td>":"</td> <td>2</td> <td>{ "boo", "and:foo" }</td></tr> + * <tr><td>":"</td> <td>t</td> <td>{ "boo", "and", "foo" }</td></tr> + * <tr><td>":"</td> <td>-2</td> <td>{ "boo", "and", "foo" }</td></tr> + * <tr><td>"o"</td> <td>5</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> + * <tr><td>"o"</td> <td>-2</td> <td>{ "b", "", ":and:f", "", "" }</td></tr> + * <tr><td>"o"</td> <td>0</td> <td>{ "b", "", ":and:f" }</td></tr> + * </table> + * + * <p>This is shorthand for + * <code>{@link Pattern}.compile(regex).split(this, limit)</code>. + * + * @param regex the pattern to match + * @param limit the limit threshold + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex, int limit) + { + return Pattern.compile(regex).split(this, limit); + } + + /** + * Split this string around the matches of a regular expression. Each + * element of the returned array is the largest block of characters not + * terminated by the regular expression, in the order the matches are found. + * The array length is unlimited, and trailing empty entries are discarded, + * as though calling <code>split(regex, 0)</code>. + * + * @param regex the pattern to match + * @return the array of split strings + * @throws NullPointerException if regex or replacement is null + * @throws PatternSyntaxException if regex is invalid + * @see #split(String, int) + * @see Pattern#compile(String) + * @see Pattern#split(CharSequence, int) + * @since 1.4 + */ + public String[] split(String regex) + { + return Pattern.compile(regex).split(this, 0); + } + + /** + * Lowercases this String according to a particular locale. This uses + * Unicode's special case mappings, as applied to the given Locale, so the + * resulting string may be a different length. + * + * @param loc locale to use + * @return new lowercased String, or this if no characters were lowercased + * @throws NullPointerException if loc is null + * @see #toUpperCase(Locale) + * @since 1.1 + */ + public native String toLowerCase(Locale locale); + + /** + * Lowercases this String. This uses Unicode's special case mappings, as + * applied to the platform's default Locale, so the resulting string may + * be a different length. + * + * @return new lowercased String, or this if no characters were lowercased + * @see #toLowerCase(Locale) + * @see #toUpperCase() + */ + public String toLowerCase() + { + // The JDK is a bit confused about what to do here. If we pass in + // the default Locale then special Locale handling might be + // invoked. However, the docs also say that Character.toLowerCase + // rules here. We go with the latter. + return toLowerCase (null); + } + + /** + * Uppercases this String according to a particular locale. This uses + * Unicode's special case mappings, as applied to the given Locale, so the + * resulting string may be a different length. + * + * @param loc locale to use + * @return new uppercased String, or this if no characters were uppercased + * @throws NullPointerException if loc is null + * @see #toLowerCase(Locale) + * @since 1.1 + */ + public native String toUpperCase(Locale locale); + + /** + * Uppercases this String. This uses Unicode's special case mappings, as + * applied to the platform's default Locale, so the resulting string may + * be a different length. + * + * @return new uppercased String, or this if no characters were uppercased + * @see #toUpperCase(Locale) + * @see #toLowerCase() + */ + public String toUpperCase() + { + // The JDK is a bit confused about what to do here. If we pass in + // the default Locale then special Locale handling might be + // invoked. However, the docs also say that Character.toLowerCase + // rules here. We go with the latter. + return toUpperCase (null); + } + + /** + * Trims all characters less than or equal to <code>'\u0020'</code> + * (<code>' '</code>) from the beginning and end of this String. This + * includes many, but not all, ASCII control characters, and all + * {@link Character#whitespace(char)}. + * + * @return new trimmed String, or this if nothing trimmed + */ + public native String trim(); + + /** + * Returns this, as it is already a String! + * + * @return this + */ + public String toString() + { + return this; + } + + /** + * Copies the contents of this String into a character array. Subsequent + * changes to the array do not affect the String. + * + * @return character array copying the String + */ + public native char[] toCharArray(); + + /** + * Returns a String representation of an Object. This is "null" if the + * object is null, otherwise it is <code>obj.toString()</code> (which + * can be null). + * + * @param obj the Object + * @return the string conversion of obj + */ + public static String valueOf(Object obj) + { + return obj == null ? "null" : obj.toString(); + } + + /** + * Returns a String representation of a character array. Subsequent + * changes to the array do not affect the String. + * + * @param data the character array + * @return a String containing the same character sequence as data + * @throws NullPointerException if data is null + * @see #valueOf(char[], int, int) + * @see #String(char[]) + */ + public static String valueOf(char[] data) + { + return valueOf (data, 0, data.length); + } + + /** + * Returns a String representing the character sequence of the char array, + * starting at the specified offset, and copying chars up to the specified + * count. Subsequent changes to the array do not affect the String. + * + * @param data character array + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @return String containing the chars from data[offset..offset+count] + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(char[], int, int) + */ + public static native String valueOf(char[] data, int offset, int count); + + /** + * Returns a String representing the character sequence of the char array, + * starting at the specified offset, and copying chars up to the specified + * count. Subsequent changes to the array do not affect the String. + * + * @param data character array + * @param offset position (base 0) to start copying out of data + * @param count the number of characters from data to copy + * @return String containing the chars from data[offset..offset+count] + * @throws NullPointerException if data is null + * @throws IndexOutOfBoundsException if (offset < 0 || count < 0 + * || offset + count > data.length) + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #String(char[], int, int) + */ + public static String copyValueOf(char[] data, int offset, int count) + { + String r = new String (); + r.init(data, offset, count, false); + return r; + } + + /** + * Returns a String representation of a character array. Subsequent + * changes to the array do not affect the String. + * + * @param data the character array + * @return a String containing the same character sequence as data + * @throws NullPointerException if data is null + * @see #copyValueOf(char[], int, int) + * @see #String(char[]) + */ + public static String copyValueOf(char[] data) + { + return copyValueOf (data, 0, data.length); + } + + /** + * Returns a String representing a boolean. + * + * @param b the boolean + * @return "true" if b is true, else "false" + */ + public static String valueOf(boolean b) + { + return b ? "true" : "false"; + } + + /** + * Returns a String representing a character. + * + * @param c the character + * @return String containing the single character c + */ + public static native String valueOf(char c); + + /** + * Returns a String representing an integer. + * + * @param i the integer + * @return String containing the integer in base 10 + * @see Integer#toString(int) + */ + public static native String valueOf(int i); + + /** + * Returns a String representing a long. + * + * @param l the long + * @return String containing the long in base 10 + * @see Long#toString(long) + */ + public static String valueOf(long l) + { + return Long.toString(l); + } + + /** + * Returns a String representing a float. + * + * @param f the float + * @return String containing the float + * @see Float#toString(float) + */ + public static String valueOf(float f) + { + return Float.toString(f); + } + + /** + * Returns a String representing a double. + * + * @param d the double + * @return String containing the double + * @see Double#toString(double) + */ + public static String valueOf(double d) + { + return Double.toString(d); + } + + /** + * Fetches this String from the intern hashtable. If two Strings are + * considered equal, by the equals() method, then intern() will return the + * same String instance. ie. if (s1.equals(s2)) then + * (s1.intern() == s2.intern()). All string literals and string-valued + * constant expressions are already interned. + * + * @return the interned String + */ + public native String intern(); + + /** + * Return the number of code points between two indices in the + * <code>String</code>. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public synchronized int codePointCount(int start, int end) + { + if (start < 0 || end > count || start > end) + throw new StringIndexOutOfBoundsException(); + + int count = 0; + while (start < end) + { + char base = charAt(start); + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == end + || start == count + || charAt(start + 1) < Character.MIN_LOW_SURROGATE + || charAt(start + 1) > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + ++count; + } + return count; + } + + /** + * Returns true iff this String contains the sequence of Characters + * described in s. + * @param s the CharSequence + * @return true iff this String contains s + * + * @since 1.5 + */ + public boolean contains (CharSequence s) + { + return this.indexOf(s.toString()) != -1; + } + + /** + * Returns a string that is this string with all instances of the sequence + * represented by <code>target</code> replaced by the sequence in + * <code>replacement</code>. + * @param target the sequence to be replaced + * @param replacement the sequence used as the replacement + * @return the string constructed as above + */ + public String replace (CharSequence target, CharSequence replacement) + { + String targetString = target.toString(); + String replaceString = replacement.toString(); + int targetLength = target.length(); + int replaceLength = replacement.length(); + + int startPos = this.indexOf(targetString); + StringBuilder result = new StringBuilder(this); + while (startPos != -1) + { + // Replace the target with the replacement + result.replace(startPos, startPos + targetLength, replaceString); + + // Search for a new occurrence of the target + startPos = result.indexOf(targetString, startPos + replaceLength); + } + return result.toString(); + } + + + private native void init(char[] chars, int offset, int count, + boolean dont_copy); + private native void init(byte[] chars, int hibyte, int offset, int count); + private native void init(byte[] chars, int offset, int count, String enc) + throws UnsupportedEncodingException; + private native void init(gnu.gcj.runtime.StringBuffer buffer); +} diff --git a/gcc-4.2.1/libjava/java/lang/StringBuffer.java b/gcc-4.2.1/libjava/java/lang/StringBuffer.java new file mode 100644 index 000000000..c3f112967 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/StringBuffer.java @@ -0,0 +1,1178 @@ +/* StringBuffer.java -- Growable strings + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.Serializable; + +/** + * <code>StringBuffer</code> represents a changeable <code>String</code>. + * It provides the operations required to modify the + * <code>StringBuffer</code>, including insert, replace, delete, append, + * and reverse. It is thread-safe; meaning that all modifications to a buffer + * are in synchronized methods. + * + * <p><code>StringBuffer</code>s are variable-length in nature, so even if + * you initialize them to a certain size, they can still grow larger than + * that. <em>Capacity</em> indicates the number of characters the + * <code>StringBuffer</code> can have in it before it has to grow (growing + * the char array is an expensive operation involving <code>new</code>). + * + * <p>Incidentally, compilers often implement the String operator "+" + * by using a <code>StringBuffer</code> operation:<br> + * <code>a + b</code><br> + * is the same as<br> + * <code>new StringBuffer().append(a).append(b).toString()</code>. + * + * <p>Classpath's StringBuffer is capable of sharing memory with Strings for + * efficiency. This will help when a StringBuffer is converted to a String + * and the StringBuffer is not changed after that (quite common when performing + * string concatenation). + * + * @author Paul Fisher + * @author John Keiser + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @see String + * @since 1.0 + * @status updated to 1.4 + */ +public final class StringBuffer implements Serializable, CharSequence +{ + /** + * Compatible with JDK 1.0+. + */ + private static final long serialVersionUID = 3388685877147921107L; + + /** + * Index of next available character (and thus the size of the current + * string contents). Note that this has permissions set this way so that + * String can get the value. + * + * @serial the number of characters in the buffer + */ + int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + char[] value; + + /** + * True if the buffer is shared with another object (StringBuffer or + * String); this means the buffer must be copied before writing to it again. + * Note that this has permissions set this way so that String can get the + * value. + * + * @serial whether the buffer is shared + */ + boolean shared; + + /** + * The default capacity of a buffer. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * Create a new StringBuffer with default capacity 16. + */ + public StringBuffer() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty <code>StringBuffer</code> with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public StringBuffer(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new <code>StringBuffer</code> with the characters in the + * specified <code>String</code>. Initial capacity will be the size of the + * String plus 16. + * + * @param str the <code>String</code> to convert + * @throws NullPointerException if str is null + */ + public StringBuffer(String str) + { + // Unfortunately, because the size is 16 larger, we cannot share. + count = str.count; + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new <code>StringBuffer</code> with the characters from the + * specified <code>CharSequence</code>. Initial capacity will be the + * size of the CharSequence plus 16. + * + * @param sequence the <code>String</code> to convert + * @throws NullPointerException if str is null + * + * @since 1.5 + */ + public StringBuffer(CharSequence sequence) + { + count = Math.max(0, sequence.length()); + value = new char[count + DEFAULT_CAPACITY]; + for (int i = 0; i < count; ++i) + value[i] = sequence.charAt(i); + } + + /** + * Get the length of the <code>String</code> this <code>StringBuffer</code> + * would create. Not to be confused with the <em>capacity</em> of the + * <code>StringBuffer</code>. + * + * @return the length of this <code>StringBuffer</code> + * @see #capacity() + * @see #setLength(int) + */ + public synchronized int length() + { + return count; + } + + /** + * Get the total number of characters this <code>StringBuffer</code> can + * support before it must be grown. Not to be confused with <em>length</em>. + * + * @return the capacity of this <code>StringBuffer</code> + * @see #length() + * @see #ensureCapacity(int) + */ + public synchronized int capacity() + { + return value.length; + } + + /** + * Increase the capacity of this <code>StringBuffer</code>. This will + * ensure that an expensive growing operation will not occur until + * <code>minimumCapacity</code> is reached. The buffer is grown to the + * larger of <code>minimumCapacity</code> and + * <code>capacity() * 2 + 2</code>, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + public synchronized void ensureCapacity(int minimumCapacity) + { + ensureCapacity_unsynchronized(minimumCapacity); + } + + /** + * Set the length of this StringBuffer. If the new length is greater than + * the current length, all the new characters are set to '\0'. If the new + * length is less than the current length, the first <code>newLength</code> + * characters of the old array will be preserved, and the remaining + * characters are truncated. + * + * @param newLength the new length + * @throws IndexOutOfBoundsException if the new length is negative + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #length() + */ + public synchronized void setLength(int newLength) + { + if (newLength < 0) + throw new StringIndexOutOfBoundsException(newLength); + + int valueLength = value.length; + + /* Always call ensureCapacity_unsynchronized in order to preserve + copy-on-write semantics. */ + ensureCapacity_unsynchronized(newLength); + + if (newLength < valueLength) + { + /* If the StringBuffer's value just grew, then we know that + value is newly allocated and the region between count and + newLength is filled with '\0'. */ + count = newLength; + } + else + { + /* The StringBuffer's value doesn't need to grow. However, + we should clear out any cruft that may exist. */ + while (count < newLength) + value[count++] = '\0'; + } + } + + /** + * Get the character at the specified index. + * + * @param index the index of the character to get, starting at 0 + * @return the character at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + */ + public synchronized char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[index]; + } + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public synchronized int codePointAt(int index) + { + return Character.codePointAt(value, index, count); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at <code>index-1</code> and + * <code>index-2</code> to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public synchronized int codePointBefore(int index) + { + // Character.codePointBefore() doesn't perform this check. We + // could use the CharSequence overload, but this is just as easy. + if (index >= count) + throw new IndexOutOfBoundsException(); + return Character.codePointBefore(value, index, 1); + } + + /** + * Get the specified array of characters. <code>srcOffset - srcEnd</code> + * characters will be copied into the array you pass in. + * + * @param srcOffset the index to start copying from (inclusive) + * @param srcEnd the index to stop copying from (exclusive) + * @param dst the array to copy into + * @param dstOffset the index to start copying into + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any source or target indices are + * out of range (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dest problems cause an + * ArrayIndexOutOfBoundsException) + * @see System#arraycopy(Object, int, Object, int, int) + */ + public synchronized void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) + throw new StringIndexOutOfBoundsException(); + System.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset); + } + + /** + * Set the character at the specified index. + * + * @param index the index of the character to set starting at 0 + * @param ch the value to set that character to + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public synchronized void setCharAt(int index, char ch) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity_unsynchronized(count); + value[index] = ch; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param obj the <code>Object</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(Object) + * @see #append(String) + */ + public StringBuffer append(Object obj) + { + return append(obj == null ? "null" : obj.toString()); + } + + /** + * Append the <code>String</code> to this <code>StringBuffer</code>. If + * str is null, the String "null" is appended. + * + * @param str the <code>String</code> to append + * @return this <code>StringBuffer</code> + */ + public synchronized StringBuffer append(String str) + { + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity_unsynchronized(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + /** + * Append the <code>StringBuffer</code> value of the argument to this + * <code>StringBuffer</code>. This behaves the same as + * <code>append((Object) stringBuffer)</code>, except it is more efficient. + * + * @param stringBuffer the <code>StringBuffer</code> to convert and append + * @return this <code>StringBuffer</code> + * @see #append(Object) + * @since 1.4 + */ + public synchronized StringBuffer append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.count; + ensureCapacity_unsynchronized(count + len); + System.arraycopy(stringBuffer.value, 0, value, count, len); + count += len; + } + return this; + } + + /** + * Append the <code>CharSequence</code> value of the argument to this + * <code>StringBuffer</code>. + * + * @param sequence the <code>CharSequence</code> to append + * @return this <code>StringBuffer</code> + * @see #append(Object) + * @since 1.5 + */ + public synchronized StringBuffer append(CharSequence sequence) + { + if (sequence == null) + sequence = "null"; + return append(sequence, 0, sequence.length()); + } + + /** + * Append the specified subsequence of the <code>CharSequence</code> + * argument to this <code>StringBuffer</code>. + * + * @param sequence the <code>CharSequence</code> to append + * @param start the starting index + * @param end one past the ending index + * @return this <code>StringBuffer</code> + * @see #append(Object) + * @since 1.5 + */ + public synchronized StringBuffer append(CharSequence sequence, + int start, int end) + { + if (sequence == null) + sequence = "null"; + if (start < 0 || end < 0 || start > end || end > sequence.length()) + throw new IndexOutOfBoundsException(); + ensureCapacity_unsynchronized(this.count + end - start); + for (int i = start; i < end; ++i) + value[count++] = sequence.charAt(i); + return this; + } + + /** + * Append the <code>char</code> array to this <code>StringBuffer</code>. + * This is similar (but more efficient) than + * <code>append(new String(data))</code>, except in the case of null. + * + * @param data the <code>char[]</code> to append + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @see #append(char[], int, int) + */ + public StringBuffer append(char[] data) + { + return append(data, 0, data.length); + } + + /** + * Append part of the <code>char</code> array to this + * <code>StringBuffer</code>. This is similar (but more efficient) than + * <code>append(new String(data, offset, count))</code>, except in the case + * of null. + * + * @param data the <code>char[]</code> to append + * @param offset the start location in <code>str</code> + * @param count the number of characters to get from <code>str</code> + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public synchronized StringBuffer append(char[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset > data.length - count) + throw new StringIndexOutOfBoundsException(); + ensureCapacity_unsynchronized(this.count + count); + System.arraycopy(data, offset, value, this.count, count); + this.count += count; + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param bool the <code>boolean</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(boolean) + */ + public StringBuffer append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the <code>char</code> to this <code>StringBuffer</code>. + * + * @param ch the <code>char</code> to append + * @return this <code>StringBuffer</code> + */ + public synchronized StringBuffer append(char ch) + { + ensureCapacity_unsynchronized(count + 1); + value[count++] = ch; + return this; + } + + /** + * Append the code point to this <code>StringBuffer</code>. + * This is like #append(char), but will append two characters + * if a supplementary code point is given. + * + * @param code the code point to append + * @return this <code>StringBuffer</code> + * @see Character#toChars(int, char[], int) + * @since 1.5 + */ + public synchronized StringBuffer appendCodePoint(int code) + { + int len = Character.charCount(code); + ensureCapacity_unsynchronized(count + len); + Character.toChars(code, value, count); + count += len; + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param inum the <code>int</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(int) + */ + // GCJ LOCAL: this is native for efficiency. + public native StringBuffer append (int inum); + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param lnum the <code>long</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(long) + */ + public StringBuffer append(long lnum) + { + return append(Long.toString(lnum, 10)); + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param fnum the <code>float</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(float) + */ + public StringBuffer append(float fnum) + { + return append(Float.toString(fnum)); + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param dnum the <code>double</code> to convert and append + * @return this <code>StringBuffer</code> + * @see String#valueOf(double) + */ + public StringBuffer append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * Delete characters from this <code>StringBuffer</code>. + * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @since 1.2 + */ + public synchronized StringBuffer delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + // This will unshare if required. + ensureCapacity_unsynchronized(count); + if (count - end != 0) + System.arraycopy(value, end, value, start, count - end); + count -= end - start; + return this; + } + + /** + * Delete a character from this <code>StringBuffer</code>. + * + * @param index the index of the character to delete + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if index is out of bounds + * @since 1.2 + */ + public StringBuffer deleteCharAt(int index) + { + return delete(index, index + 1); + } + + /** + * Replace characters between index <code>start</code> (inclusive) and + * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code> + * is larger than the size of this StringBuffer, all characters after + * <code>start</code> are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new <code>String</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + * @since 1.2 + */ + public synchronized StringBuffer replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.count; + // Calculate the difference in 'count' after the replace. + int delta = len - (end > count ? count : end) + start; + ensureCapacity_unsynchronized(count + delta); + + if (delta != 0 && end < count) + System.arraycopy(value, end, value, end + delta, count - end); + + str.getChars(0, len, value, start); + count += delta; + return this; + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at the end of this StringBuffer. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuffer + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + * @since 1.2 + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at one character before a specified index. This is implemented + * the same as <code>substring(beginIndex, endIndex)</code>, to satisfy + * the CharSequence interface. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuffer + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + * @since 1.4 + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this StringBuffer, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuffer + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + * @since 1.2 + */ + public synchronized String substring(int beginIndex, int endIndex) + { + int len = endIndex - beginIndex; + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + if (len == 0) + return ""; + // Don't copy unless substring is smaller than 1/4 of the buffer. + boolean share_buffer = ((len << 2) >= value.length); + if (share_buffer) + this.shared = true; + // Package constructor avoids an array copy. + return new String(value, beginIndex, len, share_buffer); + } + + /** + * Insert a subarray of the <code>char[]</code> argument into this + * <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param str the <code>char[]</code> to insert + * @param str_offset the index in <code>str</code> to start inserting from + * @param len the number of characters to insert + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if any index is out of bounds + * @since 1.2 + */ + public synchronized StringBuffer insert(int offset, + char[] str, int str_offset, int len) + { + if (offset < 0 || offset > count || len < 0 + || str_offset < 0 || str_offset > str.length - len) + throw new StringIndexOutOfBoundsException(); + ensureCapacity_unsynchronized(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + System.arraycopy(str, str_offset, value, offset, len); + count += len; + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param obj the <code>Object</code> to convert and insert + * @return this <code>StringBuffer</code> + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public StringBuffer insert(int offset, Object obj) + { + return insert(offset, obj == null ? "null" : obj.toString()); + } + + /** + * Insert the <code>String</code> argument into this + * <code>StringBuffer</code>. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the <code>String</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public synchronized StringBuffer insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity_unsynchronized(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + count += len; + return this; + } + + /** + * Insert the <code>CharSequence</code> argument into this + * <code>StringBuffer</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @return this <code>StringBuffer</code> + * @throws IndexOutOfBoundsException if offset is out of bounds + * @since 1.5 + */ + public synchronized StringBuffer insert(int offset, CharSequence sequence) + { + if (sequence == null) + sequence = "null"; + return insert(offset, sequence, 0, sequence.length()); + } + + /** + * Insert a subsequence of the <code>CharSequence</code> argument into this + * <code>StringBuffer</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this <code>StringBuffer</code> + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + * @since 1.5 + */ + public synchronized StringBuffer insert(int offset, CharSequence sequence, + int start, int end) + { + if (sequence == null) + sequence = "null"; + if (start < 0 || end < 0 || start > end || end > sequence.length()) + throw new IndexOutOfBoundsException(); + int len = end - start; + ensureCapacity_unsynchronized(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + for (int i = start; i < end; ++i) + value[offset++] = sequence.charAt(i); + count += len; + return this; + } + + /** + * Insert the <code>char[]</code> argument into this + * <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param data the <code>char[]</code> to insert + * @return this <code>StringBuffer</code> + * @throws NullPointerException if <code>data</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public StringBuffer insert(int offset, char[] data) + { + return insert(offset, data, 0, data.length); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param bool the <code>boolean</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public StringBuffer insert(int offset, boolean bool) + { + return insert(offset, bool ? "true" : "false"); + } + + /** + * Insert the <code>char</code> argument into this <code>StringBuffer</code>. + * + * @param offset the place to insert in this buffer + * @param ch the <code>char</code> to insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public synchronized StringBuffer insert(int offset, char ch) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + ensureCapacity_unsynchronized(count + 1); + System.arraycopy(value, offset, value, offset + 1, count - offset); + value[offset] = ch; + count++; + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param inum the <code>int</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public StringBuffer insert(int offset, int inum) + { + return insert(offset, String.valueOf(inum)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param lnum the <code>long</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public StringBuffer insert(int offset, long lnum) + { + return insert(offset, Long.toString(lnum, 10)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param fnum the <code>float</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public StringBuffer insert(int offset, float fnum) + { + return insert(offset, Float.toString(fnum)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param dnum the <code>double</code> to convert and insert + * @return this <code>StringBuffer</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public StringBuffer insert(int offset, double dnum) + { + return insert(offset, Double.toString(dnum)); + } + + /** + * Finds the first instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #indexOf(String, int) + * @since 1.4 + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this StringBuffer, starting at + * a given index. If starting index is less than 0, the search starts at + * the beginning of this String. If the starting index is greater than the + * length of this String, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public synchronized int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int limit = count - str.count; + for ( ; fromIndex <= limit; fromIndex++) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #lastIndexOf(String, int) + * @since 1.4 + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this StringBuffer, starting at a + * given index. If starting index is greater than the maximum valid index, + * then the search begins at the end of this String. If the starting index + * is less than zero, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public synchronized int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.count); + for ( ; fromIndex >= 0; fromIndex--) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Reverse the characters in this StringBuffer. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this <code>StringBuffer</code> + */ + public synchronized StringBuffer reverse() + { + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity_unsynchronized(count); + for (int i = count >> 1, j = count - i; --i >= 0; ++j) + { + char c = value[i]; + value[i] = value[j]; + value[j] = c; + } + return this; + } + + /** + * Convert this <code>StringBuffer</code> to a <code>String</code>. The + * String is composed of the characters currently in this StringBuffer. Note + * that the result is a copy, and that future modifications to this buffer + * do not affect the String. + * + * @return the characters in this StringBuffer + */ + public String toString() + { + // The string will set this.shared = true. + return new String(this); + } + + /** + * This may reduce the amount of memory used by the StringBuffer, + * by resizing the internal array to remove unused space. However, + * this method is not required to resize, so this behavior cannot + * be relied upon. + * @since 1.5 + */ + public synchronized void trimToSize() + { + int wouldSave = value.length - count; + // Some random heuristics: if we save less than 20 characters, who + // cares. + if (wouldSave < 20) + return; + // If we save more than 200 characters, shrink. + // If we save more than 1/4 of the buffer, shrink. + if (wouldSave > 200 || wouldSave * 4 > value.length) + { + char[] newValue = new char[count]; + System.arraycopy(value, 0, newValue, 0, count); + value = newValue; + } + } + + /** + * Return the number of code points between two indices in the + * <code>StringBuffer</code>. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public synchronized int codePointCount(int start, int end) + { + if (start < 0 || end >= count || start > end) + throw new StringIndexOutOfBoundsException(); + + int count = 0; + while (start < end) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == end + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + ++count; + } + return count; + } + + /** + * Starting at the given index, this counts forward by the indicated + * number of code points, and then returns the resulting index. An + * unpaired surrogate counts as a single code point for this + * purpose. + * + * @param start the starting index + * @param codePoints the number of code points + * @return the resulting index + * @since 1.5 + */ + public synchronized int offsetByCodePoints(int start, int codePoints) + { + while (codePoints > 0) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + --codePoints; + } + return start; + } + + /** + * An unsynchronized version of ensureCapacity, used internally to avoid + * the cost of a second lock on the same object. This also has the side + * effect of duplicating the array, if it was shared (to form copy-on-write + * semantics). + * + * @param minimumCapacity the minimum capacity + * @see #ensureCapacity(int) + */ + private void ensureCapacity_unsynchronized(int minimumCapacity) + { + if (shared || minimumCapacity > value.length) + { + // We don't want to make a larger vector when `shared' is + // set. If we do, then setLength becomes very inefficient + // when repeatedly reusing a StringBuffer in a loop. + int max = (minimumCapacity > value.length + ? value.length * 2 + 2 + : value.length); + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + char[] nb = new char[minimumCapacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + shared = false; + } + } + + /** + * Predicate which determines if a substring of this matches another String + * starting at a specified offset for each String and continuing for a + * specified length. This is more efficient than creating a String to call + * indexOf on. + * + * @param toffset index to start comparison at for this String + * @param other non-null String to compare to region of this + * @return true if regions match, false otherwise + * @see #indexOf(String, int) + * @see #lastIndexOf(String, int) + * @see String#regionMatches(boolean, int, String, int, int) + */ + // GCJ LOCAL: native for gcj. + private native boolean regionMatches(int toffset, String other); +} diff --git a/gcc-4.2.1/libjava/java/lang/StringBuilder.java b/gcc-4.2.1/libjava/java/lang/StringBuilder.java new file mode 100644 index 000000000..5990a6d8d --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/StringBuilder.java @@ -0,0 +1,1002 @@ +/* StringBuilder.java -- Unsynchronized growable strings + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.Serializable; + +/** + * <code>StringBuilder</code> represents a changeable <code>String</code>. + * It provides the operations required to modify the + * <code>StringBuilder</code>, including insert, replace, delete, append, + * and reverse. It like <code>StringBuffer</code>, but is not + * synchronized. It is ideal for use when it is known that the + * object will only be used from a single thread. + * + * <p><code>StringBuilder</code>s are variable-length in nature, so even if + * you initialize them to a certain size, they can still grow larger than + * that. <em>Capacity</em> indicates the number of characters the + * <code>StringBuilder</code> can have in it before it has to grow (growing + * the char array is an expensive operation involving <code>new</code>). + * + * <p>Incidentally, compilers often implement the String operator "+" + * by using a <code>StringBuilder</code> operation:<br> + * <code>a + b</code><br> + * is the same as<br> + * <code>new StringBuilder().append(a).append(b).toString()</code>. + * + * <p>Classpath's StringBuilder is capable of sharing memory with Strings for + * efficiency. This will help when a StringBuilder is converted to a String + * and the StringBuilder is not changed after that (quite common when + * performing string concatenation). + * + * @author Paul Fisher + * @author John Keiser + * @author Tom Tromey + * @author Eric Blake (ebb9@email.byu.edu) + * @see String + * @see StringBuffer + * + * @since 1.5 + */ +// FIX15: Implement Appendable when co-variant methods are available +public final class StringBuilder + implements Serializable, CharSequence +{ + // Implementation note: if you change this class, you usually will + // want to change StringBuffer as well. + + /** + * For compatability with Sun's JDK + */ + private static final long serialVersionUID = 4383685877147921099L; + + /** + * Index of next available character (and thus the size of the current + * string contents). Note that this has permissions set this way so that + * String can get the value. + * + * @serial the number of characters in the buffer + */ + int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + char[] value; + + /** + * The default capacity of a buffer. + */ + private static final int DEFAULT_CAPACITY = 16; + + /** + * Create a new StringBuilder with default capacity 16. + */ + public StringBuilder() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty <code>StringBuilder</code> with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public StringBuilder(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new <code>StringBuilder</code> with the characters in the + * specified <code>String</code>. Initial capacity will be the size of the + * String plus 16. + * + * @param str the <code>String</code> to convert + * @throws NullPointerException if str is null + */ + public StringBuilder(String str) + { + // Unfortunately, because the size is 16 larger, we cannot share. + count = str.count; + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new <code>StringBuilder</code> with the characters in the + * specified <code>CharSequence</code>. Initial capacity will be the + * length of the sequence plus 16; if the sequence reports a length + * less than or equal to 0, then the initial capacity will be 16. + * + * @param seq the initializing <code>CharSequence</code> + * @throws NullPointerException if str is null + */ + public StringBuilder(CharSequence seq) + { + int len = seq.length(); + count = len <= 0 ? 0 : len; + value = new char[count + DEFAULT_CAPACITY]; + for (int i = 0; i < len; ++i) + value[i] = seq.charAt(i); + } + + /** + * Get the length of the <code>String</code> this <code>StringBuilder</code> + * would create. Not to be confused with the <em>capacity</em> of the + * <code>StringBuilder</code>. + * + * @return the length of this <code>StringBuilder</code> + * @see #capacity() + * @see #setLength(int) + */ + public int length() + { + return count; + } + + /** + * Get the total number of characters this <code>StringBuilder</code> can + * support before it must be grown. Not to be confused with <em>length</em>. + * + * @return the capacity of this <code>StringBuilder</code> + * @see #length() + * @see #ensureCapacity(int) + */ + public int capacity() + { + return value.length; + } + + /** + * Increase the capacity of this <code>StringBuilder</code>. This will + * ensure that an expensive growing operation will not occur until + * <code>minimumCapacity</code> is reached. The buffer is grown to the + * larger of <code>minimumCapacity</code> and + * <code>capacity() * 2 + 2</code>, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #capacity() + */ + public void ensureCapacity(int minimumCapacity) + { + if (minimumCapacity > value.length) + { + int max = value.length * 2 + 2; + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + char[] nb = new char[minimumCapacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + } + } + + /** + * Set the length of this StringBuilder. If the new length is greater than + * the current length, all the new characters are set to '\0'. If the new + * length is less than the current length, the first <code>newLength</code> + * characters of the old array will be preserved, and the remaining + * characters are truncated. + * + * @param newLength the new length + * @throws IndexOutOfBoundsException if the new length is negative + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #length() + */ + public void setLength(int newLength) + { + if (newLength < 0) + throw new StringIndexOutOfBoundsException(newLength); + + int valueLength = value.length; + + /* Always call ensureCapacity in order to preserve copy-on-write + semantics. */ + ensureCapacity(newLength); + + if (newLength < valueLength) + { + /* If the StringBuilder's value just grew, then we know that + value is newly allocated and the region between count and + newLength is filled with '\0'. */ + count = newLength; + } + else + { + /* The StringBuilder's value doesn't need to grow. However, + we should clear out any cruft that may exist. */ + while (count < newLength) + value[count++] = '\0'; + } + } + + /** + * Get the character at the specified index. + * + * @param index the index of the character to get, starting at 0 + * @return the character at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[index]; + } + + /** + * Get the specified array of characters. <code>srcOffset - srcEnd</code> + * characters will be copied into the array you pass in. + * + * @param srcOffset the index to start copying from (inclusive) + * @param srcEnd the index to stop copying from (exclusive) + * @param dst the array to copy into + * @param dstOffset the index to start copying into + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any source or target indices are + * out of range (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dest problems cause an + * ArrayIndexOutOfBoundsException) + * @see System#arraycopy(Object, int, Object, int, int) + */ + public void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) + throw new StringIndexOutOfBoundsException(); + System.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset); + } + + /** + * Set the character at the specified index. + * + * @param index the index of the character to set starting at 0 + * @param ch the value to set that character to + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public void setCharAt(int index, char ch) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity(count); + value[index] = ch; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param obj the <code>Object</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(Object) + * @see #append(String) + */ + public StringBuilder append(Object obj) + { + return append(obj == null ? "null" : obj.toString()); + } + + /** + * Append the <code>String</code> to this <code>StringBuilder</code>. If + * str is null, the String "null" is appended. + * + * @param str the <code>String</code> to append + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(String str) + { + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + /** + * Append the <code>StringBuilder</code> value of the argument to this + * <code>StringBuilder</code>. This behaves the same as + * <code>append((Object) stringBuffer)</code>, except it is more efficient. + * + * @param stringBuffer the <code>StringBuilder</code> to convert and append + * @return this <code>StringBuilder</code> + * @see #append(Object) + */ + public StringBuilder append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.count; + ensureCapacity(count + len); + System.arraycopy(stringBuffer.value, 0, value, count, len); + count += len; + } + return this; + } + + /** + * Append the <code>char</code> array to this <code>StringBuilder</code>. + * This is similar (but more efficient) than + * <code>append(new String(data))</code>, except in the case of null. + * + * @param data the <code>char[]</code> to append + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @see #append(char[], int, int) + */ + public StringBuilder append(char[] data) + { + return append(data, 0, data.length); + } + + /** + * Append part of the <code>char</code> array to this + * <code>StringBuilder</code>. This is similar (but more efficient) than + * <code>append(new String(data, offset, count))</code>, except in the case + * of null. + * + * @param data the <code>char[]</code> to append + * @param offset the start location in <code>str</code> + * @param count the number of characters to get from <code>str</code> + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public StringBuilder append(char[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset > data.length - count) + throw new StringIndexOutOfBoundsException(); + ensureCapacity(this.count + count); + System.arraycopy(data, offset, value, this.count, count); + this.count += count; + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param bool the <code>boolean</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(boolean) + */ + public StringBuilder append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the <code>char</code> to this <code>StringBuilder</code>. + * + * @param ch the <code>char</code> to append + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(char ch) + { + ensureCapacity(count + 1); + value[count++] = ch; + return this; + } + + /** + * Append the characters in the <code>CharSequence</code> to this + * buffer. + * + * @param seq the <code>CharSequence</code> providing the characters + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(CharSequence seq) + { + return append(seq, 0, seq.length()); + } + + /** + * Append some characters from the <code>CharSequence</code> to this + * buffer. If the argument is null, the four characters "null" are + * appended. + * + * @param seq the <code>CharSequence</code> providing the characters + * @param start the starting index + * @param end one past the final index + * @return this <code>StringBuilder</code> + */ + public StringBuilder append(CharSequence seq, int start, + int end) + { + if (seq == null) + return append("null"); + if (end - start > 0) + { + ensureCapacity(count + end - start); + for (; start < end; ++start) + value[count++] = seq.charAt(start); + } + return this; + } + + /** + * Append the code point to this <code>StringBuilder</code>. + * This is like #append(char), but will append two characters + * if a supplementary code point is given. + * + * @param code the code point to append + * @return this <code>StringBuilder</code> + * @see Character#toChars(int, char[], int) + * @since 1.5 + */ + public synchronized StringBuilder appendCodePoint(int code) + { + int len = Character.charCount(code); + ensureCapacity(count + len); + Character.toChars(code, value, count); + count += len; + return this; + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param inum the <code>int</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(int) + */ + // FIXME: this is native in libgcj in StringBuffer. + public StringBuilder append(int inum) + { + return append(String.valueOf(inum)); + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param lnum the <code>long</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(long) + */ + public StringBuilder append(long lnum) + { + return append(Long.toString(lnum, 10)); + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param fnum the <code>float</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(float) + */ + public StringBuilder append(float fnum) + { + return append(Float.toString(fnum)); + } + + /** + * Append the <code>String</code> value of the argument to this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param dnum the <code>double</code> to convert and append + * @return this <code>StringBuilder</code> + * @see String#valueOf(double) + */ + public StringBuilder append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * Delete characters from this <code>StringBuilder</code>. + * <code>delete(10, 12)</code> will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + */ + public StringBuilder delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + // This will unshare if required. + ensureCapacity(count); + if (count - end != 0) + System.arraycopy(value, end, value, start, count - end); + count -= end - start; + return this; + } + + /** + * Delete a character from this <code>StringBuilder</code>. + * + * @param index the index of the character to delete + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if index is out of bounds + */ + public StringBuilder deleteCharAt(int index) + { + return delete(index, index + 1); + } + + /** + * Replace characters between index <code>start</code> (inclusive) and + * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code> + * is larger than the size of this StringBuilder, all characters after + * <code>start</code> are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new <code>String</code> to insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + */ + public StringBuilder replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.count; + // Calculate the difference in 'count' after the replace. + int delta = len - (end > count ? count : end) + start; + ensureCapacity(count + delta); + + if (delta != 0 && end < count) + System.arraycopy(value, end, value, end + delta, count - end); + + str.getChars(0, len, value, start); + count += delta; + return this; + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at the end of this StringBuilder. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at one character before a specified index. This is implemented + * the same as <code>substring(beginIndex, endIndex)</code>, to satisfy + * the CharSequence interface. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + */ + public String substring(int beginIndex, int endIndex) + { + int len = endIndex - beginIndex; + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + if (len == 0) + return ""; + return new String(value, beginIndex, len); + } + + /** + * Insert a subarray of the <code>char[]</code> argument into this + * <code>StringBuilder</code>. + * + * @param offset the place to insert in this buffer + * @param str the <code>char[]</code> to insert + * @param str_offset the index in <code>str</code> to start inserting from + * @param len the number of characters to insert + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>str</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if any index is out of bounds + */ + public StringBuilder insert(int offset, + char[] str, int str_offset, int len) + { + if (offset < 0 || offset > count || len < 0 + || str_offset < 0 || str_offset > str.length - len) + throw new StringIndexOutOfBoundsException(); + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + System.arraycopy(str, str_offset, value, offset, len); + count += len; + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param obj the <code>Object</code> to convert and insert + * @return this <code>StringBuilder</code> + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public StringBuilder insert(int offset, Object obj) + { + return insert(offset, obj == null ? "null" : obj.toString()); + } + + /** + * Insert the <code>String</code> argument into this + * <code>StringBuilder</code>. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the <code>String</code> to insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.count; + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + count += len; + return this; + } + + /** + * Insert the <code>CharSequence</code> argument into this + * <code>StringBuilder</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @return this <code>StringBuilder</code> + * @throws IndexOutOfBoundsException if offset is out of bounds + */ + public synchronized StringBuilder insert(int offset, CharSequence sequence) + { + if (sequence == null) + sequence = "null"; + return insert(offset, sequence, 0, sequence.length()); + } + + /** + * Insert a subsequence of the <code>CharSequence</code> argument into this + * <code>StringBuilder</code>. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the <code>CharSequence</code> to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this <code>StringBuilder</code> + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + */ + public synchronized StringBuilder insert(int offset, CharSequence sequence, + int start, int end) + { + if (sequence == null) + sequence = "null"; + if (start < 0 || end < 0 || start > end || end > sequence.length()) + throw new IndexOutOfBoundsException(); + int len = end - start; + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + for (int i = start; i < end; ++i) + value[offset++] = sequence.charAt(i); + count += len; + return this; + } + + /** + * Insert the <code>char[]</code> argument into this + * <code>StringBuilder</code>. + * + * @param offset the place to insert in this buffer + * @param data the <code>char[]</code> to insert + * @return this <code>StringBuilder</code> + * @throws NullPointerException if <code>data</code> is <code>null</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public StringBuilder insert(int offset, char[] data) + { + return insert(offset, data, 0, data.length); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param bool the <code>boolean</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public StringBuilder insert(int offset, boolean bool) + { + return insert(offset, bool ? "true" : "false"); + } + + /** + * Insert the <code>char</code> argument into this <code>StringBuilder</code>. + * + * @param offset the place to insert in this buffer + * @param ch the <code>char</code> to insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public StringBuilder insert(int offset, char ch) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + ensureCapacity(count + 1); + System.arraycopy(value, offset, value, offset + 1, count - offset); + value[offset] = ch; + count++; + return this; + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param inum the <code>int</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public StringBuilder insert(int offset, int inum) + { + return insert(offset, String.valueOf(inum)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param lnum the <code>long</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public StringBuilder insert(int offset, long lnum) + { + return insert(offset, Long.toString(lnum, 10)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param fnum the <code>float</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public StringBuilder insert(int offset, float fnum) + { + return insert(offset, Float.toString(fnum)); + } + + /** + * Insert the <code>String</code> value of the argument into this + * <code>StringBuilder</code>. Uses <code>String.valueOf()</code> to convert + * to <code>String</code>. + * + * @param offset the place to insert in this buffer + * @param dnum the <code>double</code> to convert and insert + * @return this <code>StringBuilder</code> + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public StringBuilder insert(int offset, double dnum) + { + return insert(offset, Double.toString(dnum)); + } + + /** + * Finds the first instance of a substring in this StringBuilder. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #indexOf(String, int) + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this StringBuilder, starting at + * a given index. If starting index is less than 0, the search starts at + * the beginning of this String. If the starting index is greater than the + * length of this String, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int limit = count - str.count; + for ( ; fromIndex <= limit; fromIndex++) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a substring in this StringBuilder. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #lastIndexOf(String, int) + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.count); + } + + /** + * Finds the last instance of a String in this StringBuilder, starting at a + * given index. If starting index is greater than the maximum valid index, + * then the search begins at the end of this String. If the starting index + * is less than zero, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + */ + public int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.count); + for ( ; fromIndex >= 0; fromIndex--) + if (regionMatches(fromIndex, str)) + return fromIndex; + return -1; + } + + /** + * Reverse the characters in this StringBuilder. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this <code>StringBuilder</code> + */ + public StringBuilder reverse() + { + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity(count); + for (int i = count >> 1, j = count - i; --i >= 0; ++j) + { + char c = value[i]; + value[i] = value[j]; + value[j] = c; + } + return this; + } + + /** + * Convert this <code>StringBuilder</code> to a <code>String</code>. The + * String is composed of the characters currently in this StringBuilder. Note + * that the result is a copy, and that future modifications to this buffer + * do not affect the String. + * + * @return the characters in this StringBuilder + */ + public String toString() + { + return new String(this); + } + + /** + * Predicate which determines if a substring of this matches another String + * starting at a specified offset for each String and continuing for a + * specified length. This is more efficient than creating a String to call + * indexOf on. + * + * @param toffset index to start comparison at for this String + * @param other non-null String to compare to region of this + * @return true if regions match, false otherwise + * @see #indexOf(String, int) + * @see #lastIndexOf(String, int) + * @see String#regionMatches(boolean, int, String, int, int) + */ + // GCJ LOCAL: Native to access String internals properly. + private native boolean regionMatches(int toffset, String other); +} diff --git a/gcc-4.2.1/libjava/java/lang/System.java b/gcc-4.2.1/libjava/java/lang/System.java new file mode 100644 index 000000000..6b125c90a --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/System.java @@ -0,0 +1,560 @@ +/* System.java -- useful methods to interface with the system + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.classpath.SystemProperties; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.Properties; +import java.util.PropertyPermission; + +/** + * System represents system-wide resources; things that represent the + * general environment. As such, all methods are static. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @since 1.0 + * @status still missing 1.4 functionality + */ +public final class System +{ + // WARNING: System is a CORE class in the bootstrap cycle. See the comments + // in vm/reference/java/lang/Runtime for implications of this fact. + + /** + * The standard InputStream. This is assigned at startup and starts its + * life perfectly valid. Although it is marked final, you can change it + * using {@link #setIn(InputStream)} through some hefty VM magic. + * + * <p>This corresponds to the C stdin and C++ cin variables, which + * typically input from the keyboard, but may be used to pipe input from + * other processes or files. That should all be transparent to you, + * however. + */ + public static final InputStream in + = new BufferedInputStream(new FileInputStream(FileDescriptor.in)); + /** + * The standard output PrintStream. This is assigned at startup and + * starts its life perfectly valid. Although it is marked final, you can + * change it using {@link #setOut(PrintStream)} through some hefty VM magic. + * + * <p>This corresponds to the C stdout and C++ cout variables, which + * typically output normal messages to the screen, but may be used to pipe + * output to other processes or files. That should all be transparent to + * you, however. + */ + public static final PrintStream out + = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.out)), true); + /** + * The standard output PrintStream. This is assigned at startup and + * starts its life perfectly valid. Although it is marked final, you can + * change it using {@link #setErr(PrintStream)} through some hefty VM magic. + * + * <p>This corresponds to the C stderr and C++ cerr variables, which + * typically output error messages to the screen, but may be used to pipe + * output to other processes or files. That should all be transparent to + * you, however. + */ + public static final PrintStream err + = new PrintStream(new BufferedOutputStream(new FileOutputStream(FileDescriptor.err)), true); + + /** + * This class is uninstantiable. + */ + private System() + { + } + + /** + * Set {@link #in} to a new InputStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * <code>RuntimePermission("setIO")</code>. + * + * @param in the new InputStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setIn(InputStream in) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + setIn0(in); + } + + /** + * Set {@link #out} to a new PrintStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * <code>RuntimePermission("setIO")</code>. + * + * @param out the new PrintStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setOut(PrintStream out) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + + setOut0(out); + } + + /** + * Set {@link #err} to a new PrintStream. This uses some VM magic to change + * a "final" variable, so naturally there is a security check, + * <code>RuntimePermission("setIO")</code>. + * + * @param err the new PrintStream + * @throws SecurityException if permission is denied + * @since 1.1 + */ + public static void setErr(PrintStream err) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setIO")); + setErr0(err); + } + + /** + * Set the current SecurityManager. If a security manager already exists, + * then <code>RuntimePermission("setSecurityManager")</code> is checked + * first. Since this permission is denied by the default security manager, + * setting the security manager is often an irreversible action. + * + * @param sm the new SecurityManager + * @throws SecurityException if permission is denied + */ + public static synchronized void setSecurityManager(SecurityManager sm) + { + // Implementation note: the field lives in SecurityManager because of + // bootstrap initialization issues. This method is synchronized so that + // no other thread changes it to null before this thread makes the change. + if (SecurityManager.current != null) + SecurityManager.current.checkPermission + (new RuntimePermission("setSecurityManager")); + SecurityManager.current = sm; + } + + /** + * Get the current SecurityManager. If the SecurityManager has not been + * set yet, then this method returns null. + * + * @return the current SecurityManager, or null + */ + public static SecurityManager getSecurityManager() + { + return SecurityManager.current; + } + + /** + * Get the current time, measured in the number of milliseconds from the + * beginning of Jan. 1, 1970. This is gathered from the system clock, with + * any attendant incorrectness (it may be timezone dependent). + * + * @return the current time + * @see java.util.Date + */ + public static native long currentTimeMillis(); + + /** + * Get the current time, measured in nanoseconds. The result is as + * precise as possible, and is measured against a fixed epoch. + * However, unlike currentTimeMillis(), the epoch chosen is + * arbitrary and may vary by platform, etc. + * @since 1.5 + */ + public static native long nanoTime(); + + /** + * Copy one array onto another from <code>src[srcStart]</code> ... + * <code>src[srcStart+len-1]</code> to <code>dest[destStart]</code> ... + * <code>dest[destStart+len-1]</code>. First, the arguments are validated: + * neither array may be null, they must be of compatible types, and the + * start and length must fit within both arrays. Then the copying starts, + * and proceeds through increasing slots. If src and dest are the same + * array, this will appear to copy the data to a temporary location first. + * An ArrayStoreException in the middle of copying will leave earlier + * elements copied, but later elements unchanged. + * + * @param src the array to copy elements from + * @param srcStart the starting position in src + * @param dest the array to copy elements to + * @param destStart the starting position in dest + * @param len the number of elements to copy + * @throws NullPointerException if src or dest is null + * @throws ArrayStoreException if src or dest is not an array, if they are + * not compatible array types, or if an incompatible runtime type + * is stored in dest + * @throws IndexOutOfBoundsException if len is negative, or if the start or + * end copy position in either array is out of bounds + */ + public static native void arraycopy(Object src, int srcStart, + Object dest, int destStart, int len); + + /** + * Get a hash code computed by the VM for the Object. This hash code will + * be the same as Object's hashCode() method. It is usually some + * convolution of the pointer to the Object internal to the VM. It + * follows standard hash code rules, in that it will remain the same for a + * given Object for the lifetime of that Object. + * + * @param o the Object to get the hash code for + * @return the VM-dependent hash code for this Object + * @since 1.1 + */ + public static native int identityHashCode(Object o); + + /** + * Get all the system properties at once. A security check may be performed, + * <code>checkPropertiesAccess</code>. Note that a security manager may + * allow getting a single property, but not the entire group. + * + * <p>The required properties include: + * <dl> + * <dt>java.version</dt> <dd>Java version number</dd> + * <dt>java.vendor</dt> <dd>Java vendor specific string</dd> + * <dt>java.vendor.url</dt> <dd>Java vendor URL</dd> + * <dt>java.home</dt> <dd>Java installation directory</dd> + * <dt>java.vm.specification.version</dt> <dd>VM Spec version</dd> + * <dt>java.vm.specification.vendor</dt> <dd>VM Spec vendor</dd> + * <dt>java.vm.specification.name</dt> <dd>VM Spec name</dd> + * <dt>java.vm.version</dt> <dd>VM implementation version</dd> + * <dt>java.vm.vendor</dt> <dd>VM implementation vendor</dd> + * <dt>java.vm.name</dt> <dd>VM implementation name</dd> + * <dt>java.specification.version</dt> <dd>Java Runtime Environment version</dd> + * <dt>java.specification.vendor</dt> <dd>Java Runtime Environment vendor</dd> + * <dt>java.specification.name</dt> <dd>Java Runtime Environment name</dd> + * <dt>java.class.version</dt> <dd>Java class version number</dd> + * <dt>java.class.path</dt> <dd>Java classpath</dd> + * <dt>java.library.path</dt> <dd>Path for finding Java libraries</dd> + * <dt>java.io.tmpdir</dt> <dd>Default temp file path</dd> + * <dt>java.compiler</dt> <dd>Name of JIT to use</dd> + * <dt>java.ext.dirs</dt> <dd>Java extension path</dd> + * <dt>os.name</dt> <dd>Operating System Name</dd> + * <dt>os.arch</dt> <dd>Operating System Architecture</dd> + * <dt>os.version</dt> <dd>Operating System Version</dd> + * <dt>file.separator</dt> <dd>File separator ("/" on Unix)</dd> + * <dt>path.separator</dt> <dd>Path separator (":" on Unix)</dd> + * <dt>line.separator</dt> <dd>Line separator ("\n" on Unix)</dd> + * <dt>user.name</dt> <dd>User account name</dd> + * <dt>user.home</dt> <dd>User home directory</dd> + * <dt>user.dir</dt> <dd>User's current working directory</dd> + * </dl> + * + * In addition, gnu defines several other properties, where ? stands for + * each character in '0' through '9': + * <dl> + * <dt>gnu.classpath.home</dt> <dd>Path to the classpath libraries.</dd> + * <dt>gnu.classpath.version</dt> <dd>Version of the classpath libraries.</dd> + * <dt>gnu.classpath.vm.shortname</dt> <dd>Succinct version of the VM name; + * used for finding property files in file system</dd> + * <dt>gnu.classpath.home.url</dt> <dd> Base URL; used for finding + * property files in file system</dd> + * <dt>gnu.cpu.endian</dt> <dd>big or little</dd> + * <dt>gnu.java.io.encoding_scheme_alias.ISO-8859-?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.iso-8859-?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.iso8859_?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.iso-latin-_?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.latin?</dt> <dd>8859_?</dd> + * <dt>gnu.java.io.encoding_scheme_alias.UTF-8</dt> <dd>UTF8</dd> + * <dt>gnu.java.io.encoding_scheme_alias.utf-8</dt> <dd>UTF8</dd> + * </dl> + * + * @return the system properties, will never be null + * @throws SecurityException if permission is denied + */ + public static Properties getProperties() + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertiesAccess(); + return SystemProperties.getProperties(); + } + + /** + * Set all the system properties at once. A security check may be performed, + * <code>checkPropertiesAccess</code>. Note that a security manager may + * allow setting a single property, but not the entire group. An argument + * of null resets the properties to the startup default. + * + * @param properties the new set of system properties + * @throws SecurityException if permission is denied + */ + public static void setProperties(Properties properties) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertiesAccess(); + SystemProperties.setProperties(properties); + } + + /** + * Get a single system property by name. A security check may be performed, + * <code>checkPropertyAccess(key)</code>. + * + * @param key the name of the system property to get + * @return the property, or null if not found + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + */ + public static String getProperty(String key) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertyAccess(key); + else if (key.length() == 0) + throw new IllegalArgumentException("key can't be empty"); + return SystemProperties.getProperty(key); + } + + /** + * Get a single system property by name. A security check may be performed, + * <code>checkPropertyAccess(key)</code>. + * + * @param key the name of the system property to get + * @param def the default + * @return the property, or def if not found + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + */ + public static String getProperty(String key, String def) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPropertyAccess(key); + return SystemProperties.getProperty(key, def); + } + + /** + * Set a single system property by name. A security check may be performed, + * <code>checkPropertyAccess(key, "write")</code>. + * + * @param key the name of the system property to set + * @param value the new value + * @return the previous value, or null + * @throws SecurityException if permission is denied + * @throws NullPointerException if key is null + * @throws IllegalArgumentException if key is "" + * @since 1.2 + */ + public static String setProperty(String key, String value) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "write")); + return SystemProperties.setProperty(key, value); + } + + /** + * Gets the value of an environment variable. + * + * @param name the name of the environment variable + * @return the string value of the variable or null when the + * environment variable is not defined. + * @throws NullPointerException + * @throws SecurityException if permission is denied + * @since 1.5 + * @specnote This method was deprecated in some JDK releases, but + * was restored in 1.5. + */ + public static String getenv(String name) + { + if (name == null) + throw new NullPointerException(); + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("getenv." + name)); + return getenv0(name); + } + + /** + * Terminate the Virtual Machine. This just calls + * <code>Runtime.getRuntime().exit(status)</code>, and never returns. + * Obviously, a security check is in order, <code>checkExit</code>. + * + * @param status the exit status; by convention non-zero is abnormal + * @throws SecurityException if permission is denied + * @see Runtime#exit(int) + */ + public static void exit(int status) + { + Runtime.getRuntime().exit(status); + } + + /** + * Calls the garbage collector. This is only a hint, and it is up to the + * implementation what this hint suggests, but it usually causes a + * best-effort attempt to reclaim unused memory from discarded objects. + * This calls <code>Runtime.getRuntime().gc()</code>. + * + * @see Runtime#gc() + */ + public static void gc() + { + Runtime.getRuntime().gc(); + } + + /** + * Runs object finalization on pending objects. This is only a hint, and + * it is up to the implementation what this hint suggests, but it usually + * causes a best-effort attempt to run finalizers on all objects ready + * to be reclaimed. This calls + * <code>Runtime.getRuntime().runFinalization()</code>. + * + * @see Runtime#runFinalization() + */ + public static void runFinalization() + { + Runtime.getRuntime().runFinalization(); + } + + /** + * Tell the Runtime whether to run finalization before exiting the + * JVM. This is inherently unsafe in multi-threaded applications, + * since it can force initialization on objects which are still in use + * by live threads, leading to deadlock; therefore this is disabled by + * default. There may be a security check, <code>checkExit(0)</code>. This + * calls <code>Runtime.getRuntime().runFinalizersOnExit()</code>. + * + * @param finalizeOnExit whether to run finalizers on exit + * @throws SecurityException if permission is denied + * @see Runtime#runFinalizersOnExit() + * @since 1.1 + * @deprecated never rely on finalizers to do a clean, thread-safe, + * mop-up from your code + */ + public static void runFinalizersOnExit(boolean finalizeOnExit) + { + Runtime.getRuntime().runFinalizersOnExit(finalizeOnExit); + } + + /** + * Load a code file using its explicit system-dependent filename. A security + * check may be performed, <code>checkLink</code>. This just calls + * <code>Runtime.getRuntime().load(filename)</code>. + * + * <p> + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param filename the code file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the file cannot be loaded + * @see Runtime#load(String) + */ + public static void load(String filename) + { + Runtime.getRuntime().load(filename); + } + + /** + * Load a library using its explicit system-dependent filename. A security + * check may be performed, <code>checkLink</code>. This just calls + * <code>Runtime.getRuntime().load(filename)</code>. + * + * <p> + * The library is loaded using the class loader associated with the + * class associated with the invoking method. + * + * @param libname the library file to load + * @throws SecurityException if permission is denied + * @throws UnsatisfiedLinkError if the file cannot be loaded + * @see Runtime#load(String) + */ + public static void loadLibrary(String libname) + { + Runtime.getRuntime().loadLibrary(libname); + } + + /** + * Convert a library name to its platform-specific variant. + * + * @param libname the library name, as used in <code>loadLibrary</code> + * @return the platform-specific mangling of the name + * @since 1.2 + */ + public static String mapLibraryName(String libname) + { + // XXX Fix this!!!! + return Runtime.nativeGetLibname("", libname); + } + + /** + * Set {@link #in} to a new InputStream. + * + * @param in the new InputStream + * @see #setIn(InputStream) + */ + private static native void setIn0(InputStream in); + + /** + * Set {@link #out} to a new PrintStream. + * + * @param out the new PrintStream + * @see #setOut(PrintStream) + */ + private static native void setOut0(PrintStream out); + + /** + * Set {@link #err} to a new PrintStream. + * + * @param err the new PrintStream + * @see #setErr(PrintStream) + */ + private static native void setErr0(PrintStream err); + + /** + * Gets the value of an environment variable. + * + * @see #getenv(String) + */ + static native String getenv0(String name); +} // class System diff --git a/gcc-4.2.1/libjava/java/lang/Thread.java b/gcc-4.2.1/libjava/java/lang/Thread.java new file mode 100644 index 000000000..2b7fb2aec --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Thread.java @@ -0,0 +1,1128 @@ +/* Thread -- an independent thread of executable code + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang; + +import gnu.gcj.RawData; +import gnu.gcj.RawDataManaged; +import gnu.java.util.WeakIdentityHashMap; +import java.util.Map; + +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete to version 1.4, with caveats. We do not + * implement the deprecated (and dangerous) stop, suspend, and resume + * methods. Security implementation is not complete. + */ + +/** + * Thread represents a single thread of execution in the VM. When an + * application VM starts up, it creates a non-daemon Thread which calls the + * main() method of a particular class. There may be other Threads running, + * such as the garbage collection thread. + * + * <p>Threads have names to identify them. These names are not necessarily + * unique. Every Thread has a priority, as well, which tells the VM which + * Threads should get more running time. New threads inherit the priority + * and daemon status of the parent thread, by default. + * + * <p>There are two methods of creating a Thread: you may subclass Thread and + * implement the <code>run()</code> method, at which point you may start the + * Thread by calling its <code>start()</code> method, or you may implement + * <code>Runnable</code> in the class you want to use and then call new + * <code>Thread(your_obj).start()</code>. + * + * <p>The virtual machine runs until all non-daemon threads have died (either + * by returning from the run() method as invoked by start(), or by throwing + * an uncaught exception); or until <code>System.exit</code> is called with + * adequate permissions. + * + * <p>It is unclear at what point a Thread should be added to a ThreadGroup, + * and at what point it should be removed. Should it be inserted when it + * starts, or when it is created? Should it be removed when it is suspended + * or interrupted? The only thing that is clear is that the Thread should be + * removed when it is stopped. + * + * @author Tom Tromey + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @see Runnable + * @see Runtime#exit(int) + * @see #run() + * @see #start() + * @see ThreadLocal + * @since 1.0 + * @status updated to 1.4 + */ +public class Thread implements Runnable +{ + /** The minimum priority for a Thread. */ + public static final int MIN_PRIORITY = 1; + + /** The priority a Thread gets by default. */ + public static final int NORM_PRIORITY = 5; + + /** The maximum priority for a Thread. */ + public static final int MAX_PRIORITY = 10; + + /** + * The group this thread belongs to. This is set to null by + * ThreadGroup.removeThread when the thread dies. + */ + ThreadGroup group; + + /** The object to run(), null if this is the target. */ + private Runnable runnable; + + /** The thread name, non-null. */ + String name; + + /** Whether the thread is a daemon. */ + private boolean daemon; + + /** The thread priority, 1 to 10. */ + private int priority; + + boolean interrupt_flag; + private boolean alive_flag; + private boolean startable_flag; + + /** The context classloader for this Thread. */ + private ClassLoader contextClassLoader; + + /** This thread's ID. */ + private final long threadId; + + /** The next thread ID to use. */ + private static long nextThreadId; + + /** The default exception handler. */ + private static UncaughtExceptionHandler defaultHandler; + + /** Thread local storage. Package accessible for use by + * InheritableThreadLocal. + */ + WeakIdentityHashMap locals; + + /** The uncaught exception handler. */ + UncaughtExceptionHandler exceptionHandler; + + /** The access control state for this thread. Package accessible + * for use by java.security.VMAccessControlState's native method. + */ + Object accessControlState = null; + + // This describes the top-most interpreter frame for this thread. + RawData interp_frame; + + // Our native data - points to an instance of struct natThread. + private RawDataManaged data; + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, null,</code> + * <i>gname</i><code>)</code>, where <b><i>gname</i></b> is + * a newly generated name. Automatically generated names are of the + * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. + * <p> + * Threads created this way must have overridden their + * <code>run()</code> method to actually do anything. An example + * illustrating this method being used follows: + * <p><blockquote><pre> + * import java.lang.*; + * + * class plain01 implements Runnable { + * String name; + * plain01() { + * name = null; + * } + * plain01(String s) { + * name = s; + * } + * public void run() { + * if (name == null) + * System.out.println("A new thread created"); + * else + * System.out.println("A new thread with name " + name + + * " created"); + * } + * } + * class threadtest01 { + * public static void main(String args[] ) { + * int failed = 0 ; + * + * <b>Thread t1 = new Thread();</b> + * if (t1 != null) + * System.out.println("new Thread() succeed"); + * else { + * System.out.println("new Thread() failed"); + * failed++; + * } + * } + * } + * </pre></blockquote> + * + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread() + { + this(null, null, gen_name()); + } + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, target,</code> + * <i>gname</i><code>)</code>, where <i>gname</i> is + * a newly generated name. Automatically generated names are of the + * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. + * + * @param target the object whose <code>run</code> method is called. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread(Runnable target) + { + this(null, target, gen_name()); + } + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, null, name)</code>. + * + * @param name the name of the new thread. + * @see java.lang.Thread#Thread(java.lang.ThreadGroup, + * java.lang.Runnable, java.lang.String) + */ + public Thread(String name) + { + this(null, null, name); + } + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(group, target,</code> + * <i>gname</i><code>)</code>, where <i>gname</i> is + * a newly generated name. Automatically generated names are of the + * form <code>"Thread-"+</code><i>n</i>, where <i>n</i> is an integer. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(ThreadGroup group, Runnable target) + { + this(group, target, gen_name()); + } + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(group, null, name)</code> + * + * @param group the group to put the Thread into + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(ThreadGroup group, String name) + { + this(group, null, name); + } + + /** + * Allocates a new <code>Thread</code> object. This constructor has + * the same effect as <code>Thread(null, target, name)</code>. + * + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @see #Thread(ThreadGroup, Runnable, String) + */ + public Thread(Runnable target, String name) + { + this(null, target, name); + } + + /** + * Allocate a new Thread object, with the specified ThreadGroup and name, and + * using the specified Runnable object's <code>run()</code> method to + * execute. If the Runnable object is null, <code>this</code> (which is + * a Runnable) is used instead. + * + * <p>If the ThreadGroup is null, the security manager is checked. If a + * manager exists and returns a non-null object for + * <code>getThreadGroup</code>, that group is used; otherwise the group + * of the creating thread is used. Note that the security manager calls + * <code>checkAccess</code> if the ThreadGroup is not null. + * + * <p>The new Thread will inherit its creator's priority and daemon status. + * These can be changed with <code>setPriority</code> and + * <code>setDaemon</code>. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @see Runnable#run() + * @see #run() + * @see #setDaemon(boolean) + * @see #setPriority(int) + * @see SecurityManager#checkAccess(ThreadGroup) + * @see ThreadGroup#checkAccess() + */ + public Thread(ThreadGroup group, Runnable target, String name) + { + this(currentThread(), group, target, name); + } + + /** + * Allocate a new Thread object, as if by + * <code>Thread(group, null, name)</code>, and give it the specified stack + * size, in bytes. The stack size is <b>highly platform independent</b>, + * and the virtual machine is free to round up or down, or ignore it + * completely. A higher value might let you go longer before a + * <code>StackOverflowError</code>, while a lower value might let you go + * longer before an <code>OutOfMemoryError</code>. Or, it may do absolutely + * nothing! So be careful, and expect to need to tune this value if your + * virtual machine even supports it. + * + * @param group the group to put the Thread into + * @param target the Runnable object to execute + * @param name the name for the Thread + * @param size the stack size, in bytes; 0 to be ignored + * @throws NullPointerException if name is null + * @throws SecurityException if this thread cannot access <code>group</code> + * @throws IllegalThreadStateException if group is destroyed + * @since 1.4 + */ + public Thread(ThreadGroup group, Runnable target, String name, long size) + { + // Just ignore stackSize for now. + this(currentThread(), group, target, name); + } + + private Thread (Thread current, ThreadGroup g, Runnable r, String n) + { + // Make sure the current thread may create a new thread. + checkAccess(); + + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (n == null) + throw new NullPointerException (); + + if (g == null) + { + // If CURRENT is null, then we are bootstrapping the first thread. + // Use ThreadGroup.root, the main threadgroup. + if (current == null) + group = ThreadGroup.root; + else + group = current.getThreadGroup(); + } + else + group = g; + + data = null; + interrupt_flag = false; + alive_flag = false; + startable_flag = true; + + synchronized (Thread.class) + { + this.threadId = nextThreadId++; + } + + if (current != null) + { + group.checkAccess(); + + daemon = current.isDaemon(); + int gmax = group.getMaxPriority(); + int pri = current.getPriority(); + priority = (gmax < pri ? gmax : pri); + contextClassLoader = current.contextClassLoader; + InheritableThreadLocal.newChildThread(this); + } + else + { + daemon = false; + priority = NORM_PRIORITY; + } + + name = n; + group.addThread(this); + runnable = r; + + initialize_native (); + } + + /** + * Get the number of active threads in the current Thread's ThreadGroup. + * This implementation calls + * <code>currentThread().getThreadGroup().activeCount()</code>. + * + * @return the number of active threads in the current ThreadGroup + * @see ThreadGroup#activeCount() + */ + public static int activeCount() + { + return currentThread().group.activeCount(); + } + + /** + * Check whether the current Thread is allowed to modify this Thread. This + * passes the check on to <code>SecurityManager.checkAccess(this)</code>. + * + * @throws SecurityException if the current Thread cannot modify this Thread + * @see SecurityManager#checkAccess(Thread) + */ + public final void checkAccess() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkAccess(this); + } + + /** + * Count the number of stack frames in this Thread. The Thread in question + * must be suspended when this occurs. + * + * @return the number of stack frames in this Thread + * @throws IllegalThreadStateException if this Thread is not suspended + * @deprecated pointless, since suspend is deprecated + */ + public native int countStackFrames(); + + /** + * Get the currently executing Thread. + * + * @return the currently executing Thread + */ + public static native Thread currentThread(); + + /** + * Originally intended to destroy this thread, this method was never + * implemented by Sun, and is hence a no-op. + */ + public void destroy() + { + throw new NoSuchMethodError(); + } + + /** + * Print a stack trace of the current thread to stderr using the same + * format as Throwable's printStackTrace() method. + * + * @see Throwable#printStackTrace() + */ + public static void dumpStack() + { + (new Exception("Stack trace")).printStackTrace(); + } + + /** + * Copy every active thread in the current Thread's ThreadGroup into the + * array. Extra threads are silently ignored. This implementation calls + * <code>getThreadGroup().enumerate(array)</code>, which may have a + * security check, <code>checkAccess(group)</code>. + * + * @param array the array to place the Threads into + * @return the number of Threads placed into the array + * @throws NullPointerException if array is null + * @throws SecurityException if you cannot access the ThreadGroup + * @see ThreadGroup#enumerate(Thread[]) + * @see #activeCount() + * @see SecurityManager#checkAccess(ThreadGroup) + */ + public static int enumerate(Thread[] array) + { + return currentThread().group.enumerate(array); + } + + /** + * Get this Thread's name. + * + * @return this Thread's name + */ + public final String getName() + { + return name; + } + + /** + * Get this Thread's priority. + * + * @return the Thread's priority + */ + public final int getPriority() + { + return priority; + } + + /** + * Get the ThreadGroup this Thread belongs to. If the thread has died, this + * returns null. + * + * @return this Thread's ThreadGroup + */ + public final ThreadGroup getThreadGroup() + { + return group; + } + + /** + * Checks whether the current thread holds the monitor on a given object. + * This allows you to do <code>assert Thread.holdsLock(obj)</code>. + * + * @param obj the object to test lock ownership on. + * @return true if the current thread is currently synchronized on obj + * @throws NullPointerException if obj is null + * @since 1.4 + */ + public static native boolean holdsLock(Object obj); + + /** + * Interrupt this Thread. First, there is a security check, + * <code>checkAccess</code>. Then, depending on the current state of the + * thread, various actions take place: + * + * <p>If the thread is waiting because of {@link #wait()}, + * {@link #sleep(long)}, or {@link #join()}, its <i>interrupt status</i> + * will be cleared, and an InterruptedException will be thrown. Notice that + * this case is only possible if an external thread called interrupt(). + * + * <p>If the thread is blocked in an interruptible I/O operation, in + * {@link java.nio.channels.InterruptibleChannel}, the <i>interrupt + * status</i> will be set, and ClosedByInterruptException will be thrown. + * + * <p>If the thread is blocked on a {@link java.nio.channels.Selector}, the + * <i>interrupt status</i> will be set, and the selection will return, with + * a possible non-zero value, as though by the wakeup() method. + * + * <p>Otherwise, the interrupt status will be set. + * + * @throws SecurityException if you cannot modify this Thread + */ + public native void interrupt(); + + /** + * Determine whether the current Thread has been interrupted, and clear + * the <i>interrupted status</i> in the process. + * + * @return whether the current Thread has been interrupted + * @see #isInterrupted() + */ + public static boolean interrupted() + { + return currentThread().isInterrupted(true); + } + + /** + * Determine whether the given Thread has been interrupted, but leave + * the <i>interrupted status</i> alone in the process. + * + * @return whether the Thread has been interrupted + * @see #interrupted() + */ + public boolean isInterrupted() + { + return interrupt_flag; + } + + /** + * Determine whether this Thread is alive. A thread which is alive has + * started and not yet died. + * + * @return whether this Thread is alive + */ + public final synchronized boolean isAlive() + { + return alive_flag; + } + + /** + * Tell whether this is a daemon Thread or not. + * + * @return whether this is a daemon Thread or not + * @see #setDaemon(boolean) + */ + public final boolean isDaemon() + { + return daemon; + } + + /** + * Wait forever for the Thread in question to die. + * + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + */ + public final void join() throws InterruptedException + { + join(0, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + */ + public final void join(long ms) throws InterruptedException + { + join(ms, 0); + } + + /** + * Wait the specified amount of time for the Thread in question to die. + * + * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do + * not offer that fine a grain of timing resolution. Besides, there is + * no guarantee that this thread can start up immediately when time expires, + * because some other thread may be active. So don't expect real-time + * performance. + * + * @param ms the number of milliseconds to wait, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + * @throws IllegalArgumentException if ns is invalid + * @XXX A ThreadListener would be nice, to make this efficient. + */ + public final native void join(long ms, int ns) + throws InterruptedException; + + /** + * Resume a suspended thread. + * + * @throws SecurityException if you cannot resume the Thread + * @see #checkAccess() + * @see #suspend() + * @deprecated pointless, since suspend is deprecated + */ + public final native void resume(); + + private final native void finish_(); + + /** + * Determine whether the given Thread has been interrupted, but leave + * the <i>interrupted status</i> alone in the process. + * + * @return whether the current Thread has been interrupted + * @see #interrupted() + */ + private boolean isInterrupted(boolean clear_flag) + { + boolean r = interrupt_flag; + if (clear_flag && r) + { + // Only clear the flag if we saw it as set. Otherwise this could + // potentially cause us to miss an interrupt in a race condition, + // because this method is not synchronized. + interrupt_flag = false; + } + return r; + } + + /** + * The method of Thread that will be run if there is no Runnable object + * associated with the Thread. Thread's implementation does nothing at all. + * + * @see #start() + * @see #Thread(ThreadGroup, Runnable, String) + */ + public void run() + { + if (runnable != null) + runnable.run(); + } + + /** + * Set the daemon status of this Thread. If this is a daemon Thread, then + * the VM may exit even if it is still running. This may only be called + * before the Thread starts running. There may be a security check, + * <code>checkAccess</code>. + * + * @param daemon whether this should be a daemon thread or not + * @throws SecurityException if you cannot modify this Thread + * @throws IllegalThreadStateException if the Thread is active + * @see #isDaemon() + * @see #checkAccess() + */ + public final void setDaemon(boolean daemon) + { + if (!startable_flag) + throw new IllegalThreadStateException(); + checkAccess(); + this.daemon = daemon; + } + + /** + * Returns the context classloader of this Thread. The context + * classloader can be used by code that want to load classes depending + * on the current thread. Normally classes are loaded depending on + * the classloader of the current class. There may be a security check + * for <code>RuntimePermission("getClassLoader")</code> if the caller's + * class loader is not null or an ancestor of this thread's context class + * loader. + * + * @return the context class loader + * @throws SecurityException when permission is denied + * @see setContextClassLoader(ClassLoader) + * @since 1.2 + */ + public synchronized ClassLoader getContextClassLoader() + { + if (contextClassLoader == null) + contextClassLoader = ClassLoader.getSystemClassLoader(); + + SecurityManager sm = System.getSecurityManager(); + // FIXME: we can't currently find the caller's class loader. + ClassLoader callers = null; + if (sm != null && callers != null) + { + // See if the caller's class loader is the same as or an + // ancestor of this thread's class loader. + while (callers != null && callers != contextClassLoader) + { + // FIXME: should use some internal version of getParent + // that avoids security checks. + callers = callers.getParent(); + } + + if (callers != contextClassLoader) + sm.checkPermission(new RuntimePermission("getClassLoader")); + } + + return contextClassLoader; + } + + /** + * Sets the context classloader for this Thread. When not explicitly set, + * the context classloader for a thread is the same as the context + * classloader of the thread that created this thread. The first thread has + * as context classloader the system classloader. There may be a security + * check for <code>RuntimePermission("setContextClassLoader")</code>. + * + * @param classloader the new context class loader + * @throws SecurityException when permission is denied + * @see getContextClassLoader() + * @since 1.2 + */ + public synchronized void setContextClassLoader(ClassLoader classloader) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new RuntimePermission("setContextClassLoader")); + this.contextClassLoader = classloader; + } + + /** + * Set this Thread's name. There may be a security check, + * <code>checkAccess</code>. + * + * @param name the new name for this Thread + * @throws NullPointerException if name is null + * @throws SecurityException if you cannot modify this Thread + */ + public final void setName(String name) + { + checkAccess(); + // The Class Libraries book says ``threadName cannot be null''. I + // take this to mean NullPointerException. + if (name == null) + throw new NullPointerException(); + this.name = name; + } + + /** + * Causes the currently executing thread object to temporarily pause + * and allow other threads to execute. + */ + public static native void yield(); + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + * + * @param ms the number of milliseconds to sleep, or 0 for forever + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + * @see #notify() + * @see #wait(long) + */ + public static void sleep(long ms) throws InterruptedException + { + sleep(ms, 0); + } + + /** + * Suspend the current Thread's execution for the specified amount of + * time. The Thread will not lose any locks it has during this time. There + * are no guarantees which thread will be next to run, but most VMs will + * choose the highest priority thread that has been waiting longest. + * + * <p>Note that 1,000,000 nanoseconds == 1 millisecond, but most VMs do + * not offer that fine a grain of timing resolution. Besides, there is + * no guarantee that this thread can start up immediately when time expires, + * because some other thread may be active. So don't expect real-time + * performance. + * + * @param ms the number of milliseconds to sleep, or 0 for forever + * @param ns the number of extra nanoseconds to sleep (0-999999) + * @throws InterruptedException if the Thread is interrupted; it's + * <i>interrupted status</i> will be cleared + * @throws IllegalArgumentException if ns is invalid + * @see #notify() + * @see #wait(long, int) + */ + public static native void sleep(long timeout, int nanos) + throws InterruptedException; + + /** + * Start this Thread, calling the run() method of the Runnable this Thread + * was created with, or else the run() method of the Thread itself. This + * is the only way to start a new thread; calling run by yourself will just + * stay in the same thread. The virtual machine will remove the thread from + * its thread group when the run() method completes. + * + * @throws IllegalThreadStateException if the thread has already started + * @see #run() + */ + public native void start(); + + /** + * Cause this Thread to stop abnormally because of the throw of a ThreadDeath + * error. If you stop a Thread that has not yet started, it will stop + * immediately when it is actually started. + * + * <p>This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * <code>checkAccess(this)</code>, plus another one if the current thread + * is not this: <code>RuntimePermission("stopThread")</code>. If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @throws SecurityException if you cannot stop the Thread + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final void stop() + { + // Argument doesn't matter, because this is no longer + // supported. + stop(null); + } + + /** + * Cause this Thread to stop abnormally and throw the specified exception. + * If you stop a Thread that has not yet started, it will stop immediately + * when it is actually started. <b>WARNING</b>This bypasses Java security, + * and can throw a checked exception which the call stack is unprepared to + * handle. Do not abuse this power. + * + * <p>This is inherently unsafe, as it can interrupt synchronized blocks and + * leave data in bad states. Hence, there is a security check: + * <code>checkAccess(this)</code>, plus another one if the current thread + * is not this: <code>RuntimePermission("stopThread")</code>. If you must + * catch a ThreadDeath, be sure to rethrow it after you have cleaned up. + * ThreadDeath is the only exception which does not print a stack trace when + * the thread dies. + * + * @param t the Throwable to throw when the Thread dies + * @throws SecurityException if you cannot stop the Thread + * @throws NullPointerException in the calling thread, if t is null + * @see #interrupt() + * @see #checkAccess() + * @see #start() + * @see ThreadDeath + * @see ThreadGroup#uncaughtException(Thread, Throwable) + * @see SecurityManager#checkAccess(Thread) + * @see SecurityManager#checkPermission(Permission) + * @deprecated unsafe operation, try not to use + */ + public final native void stop(Throwable t); + + /** + * Suspend this Thread. It will not come back, ever, unless it is resumed. + * + * <p>This is inherently unsafe, as the suspended thread still holds locks, + * and can potentially deadlock your program. Hence, there is a security + * check: <code>checkAccess</code>. + * + * @throws SecurityException if you cannot suspend the Thread + * @see #checkAccess() + * @see #resume() + * @deprecated unsafe operation, try not to use + */ + public final native void suspend(); + + /** + * Set this Thread's priority. There may be a security check, + * <code>checkAccess</code>, then the priority is set to the smaller of + * priority and the ThreadGroup maximum priority. + * + * @param priority the new priority for this Thread + * @throws IllegalArgumentException if priority exceeds MIN_PRIORITY or + * MAX_PRIORITY + * @throws SecurityException if you cannot modify this Thread + * @see #getPriority() + * @see #checkAccess() + * @see ThreadGroup#getMaxPriority() + * @see #MIN_PRIORITY + * @see #MAX_PRIORITY + */ + public final native void setPriority(int newPriority); + + /** + * Returns a string representation of this thread, including the + * thread's name, priority, and thread group. + * + * @return a human-readable String representing this Thread + */ + public String toString() + { + return ("Thread[" + name + "," + priority + "," + + (group == null ? "" : group.getName()) + "]"); + } + + private final native void initialize_native(); + + private final native static String gen_name(); + + /** + * Returns the map used by ThreadLocal to store the thread local values. + */ + static Map getThreadLocals() + { + Thread thread = currentThread(); + Map locals = thread.locals; + if (locals == null) + { + locals = thread.locals = new WeakIdentityHashMap(); + } + return locals; + } + + /** + * Assigns the given <code>UncaughtExceptionHandler</code> to this + * thread. This will then be called if the thread terminates due + * to an uncaught exception, pre-empting that of the + * <code>ThreadGroup</code>. + * + * @param h the handler to use for this thread. + * @throws SecurityException if the current thread can't modify this thread. + * @since 1.5 + */ + public void setUncaughtExceptionHandler(UncaughtExceptionHandler h) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkAccess(this); + exceptionHandler = h; + } + + /** + * <p> + * Returns the handler used when this thread terminates due to an + * uncaught exception. The handler used is determined by the following: + * </p> + * <ul> + * <li>If this thread has its own handler, this is returned.</li> + * <li>If not, then the handler of the thread's <code>ThreadGroup</code> + * object is returned.</li> + * <li>If both are unavailable, then <code>null</code> is returned + * (which can only happen when the thread was terminated since + * then it won't have an associated thread group anymore).</li> + * </ul> + * + * @return the appropriate <code>UncaughtExceptionHandler</code> or + * <code>null</code> if one can't be obtained. + * @since 1.5 + */ + public UncaughtExceptionHandler getUncaughtExceptionHandler() + { + return exceptionHandler != null ? exceptionHandler : group; + } + + /** + * <p> + * Sets the default uncaught exception handler used when one isn't + * provided by the thread or its associated <code>ThreadGroup</code>. + * This exception handler is used when the thread itself does not + * have an exception handler, and the thread's <code>ThreadGroup</code> + * does not override this default mechanism with its own. As the group + * calls this handler by default, this exception handler should not defer + * to that of the group, as it may lead to infinite recursion. + * </p> + * <p> + * Uncaught exception handlers are used when a thread terminates due to + * an uncaught exception. Replacing this handler allows default code to + * be put in place for all threads in order to handle this eventuality. + * </p> + * + * @param h the new default uncaught exception handler to use. + * @throws SecurityException if a security manager is present and + * disallows the runtime permission + * "setDefaultUncaughtExceptionHandler". + * @since 1.5 + */ + public static void + setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler h) + { + SecurityManager sm = SecurityManager.current; // Be thread-safe. + if (sm != null) + sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler")); + defaultHandler = h; + } + + /** + * Returns the handler used by default when a thread terminates + * unexpectedly due to an exception, or <code>null</code> if one doesn't + * exist. + * + * @return the default uncaught exception handler. + * @since 1.5 + */ + public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler() + { + return defaultHandler; + } + + /** + * Returns the unique identifier for this thread. This ID is generated + * on thread creation, and may be re-used on its death. + * + * @return a positive long number representing the thread's ID. + * @since 1.5 + */ + public long getId() + { + return threadId; + } + + /** + * <p> + * This interface is used to handle uncaught exceptions + * which cause a <code>Thread</code> to terminate. When + * a thread, t, is about to terminate due to an uncaught + * exception, the virtual machine looks for a class which + * implements this interface, in order to supply it with + * the dying thread and its uncaught exception. + * </p> + * <p> + * The virtual machine makes two attempts to find an + * appropriate handler for the uncaught exception, in + * the following order: + * </p> + * <ol> + * <li> + * <code>t.getUncaughtExceptionHandler()</code> -- + * the dying thread is queried first for a handler + * specific to that thread. + * </li> + * <li> + * <code>t.getThreadGroup()</code> -- + * the thread group of the dying thread is used to + * handle the exception. If the thread group has + * no special requirements for handling the exception, + * it may simply forward it on to + * <code>Thread.getDefaultUncaughtExceptionHandler()</code>, + * the default handler, which is used as a last resort. + * </li> + * </ol> + * <p> + * The first handler found is the one used to handle + * the uncaught exception. + * </p> + * + * @author Tom Tromey <tromey@redhat.com> + * @author Andrew John Hughes <gnu_andrew@member.fsf.org> + * @since 1.5 + * @see Thread#getUncaughtExceptionHandler() + * @see Thread#setUncaughtExceptionHander(java.lang.Thread.UncaughtExceptionHandler) + * @see Thread#getDefaultUncaughtExceptionHandler() + * @see + * Thread#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler) + */ + public interface UncaughtExceptionHandler + { + /** + * Invoked by the virtual machine with the dying thread + * and the uncaught exception. Any exceptions thrown + * by this method are simply ignored by the virtual + * machine. + * + * @param thr the dying thread. + * @param exc the uncaught exception. + */ + void uncaughtException(Thread thr, Throwable exc); + } + + /** + * Returns the current state of the thread. This + * is designed for monitoring thread behaviour, rather + * than for synchronization control. + * + * @return the current thread state. + */ + public String getState() + { + // FIXME - Provide real implementation. + return "NEW"; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/VMClassLoader.java b/gcc-4.2.1/libjava/java/lang/VMClassLoader.java new file mode 100644 index 000000000..21019b757 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/VMClassLoader.java @@ -0,0 +1,348 @@ +/* VMClassLoader.java -- Reference implementation of native interface + required by ClassLoader + Copyright (C) 1998, 2001, 2002, 2003, 2004, 2005 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import gnu.java.util.EmptyEnumeration; +import java.lang.reflect.Constructor; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AllPermission; +import java.security.Permission; +import java.security.Permissions; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.StringTokenizer; +import gnu.gcj.runtime.BootClassLoader; + +/** + * java.lang.VMClassLoader is a package-private helper for VMs to implement + * on behalf of java.lang.ClassLoader. + * + * @author John Keiser + * @author Mark Wielaard <mark@klomp.org> + * @author Eric Blake <ebb9@email.byu.edu> + */ +final class VMClassLoader +{ + // Protection Domain definitions + // FIXME: should there be a special protection domain used for native code? + + // The permission required to check what a classes protection domain is. + static final Permission protectionDomainPermission + = new RuntimePermission("getProtectionDomain"); + // The protection domain returned if we cannot determine it. + static ProtectionDomain unknownProtectionDomain; + + static + { + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + unknownProtectionDomain = new ProtectionDomain(null, permissions); + } + + static final HashMap definedPackages = new HashMap(); + + // This is a helper for handling java.endorsed.dirs. It is null + // until we've initialized the system, at which point it is created. + static BootClassLoader bootLoader; + + // This keeps track of shared libraries we've already tried to load. + private static HashSet tried_libraries; + + // Holds one of the LIB_* constants; used to determine how shared + // library loads are done. + private static int lib_control; + + private static final int LIB_FULL = 0; + private static final int LIB_CACHE = 1; + private static final int LIB_NEVER = 2; + + /** + * Helper to define a class using a string of bytes. This assumes that + * the security checks have already been performed, if necessary. + * + * <strong>For backward compatibility, this just ignores the protection + * domain; that is the wrong behavior, and you should directly implement + * this method natively if you can.</strong> + * + * @param name the name to give the class, or null if unknown + * @param data the data representing the classfile, in classfile format + * @param offset the offset into the data where the classfile starts + * @param len the length of the classfile data in the array + * @param pd the protection domain + * @return the class that was defined + * @throws ClassFormatError if data is not in proper classfile format + */ + static final native Class defineClass(ClassLoader cl, String name, + byte[] data, int offset, int len, + ProtectionDomain pd) + throws ClassFormatError; + + /** + * Helper to resolve all references to other classes from this class. + * + * @param c the class to resolve + */ + static final void resolveClass(Class clazz) + { + // There doesn't seem to be a need for this to do anything. + // Testing reveals that the JDK doesn't seem to do anything here, + // either. + } + + /** + * Helper to load a class from the bootstrap class loader. + * + * @param name the class name to load + * @param resolve whether to resolve it + * @return the class, loaded by the bootstrap classloader or null + * if the class wasn't found. Returning null is equivalent to throwing + * a ClassNotFoundException (but a possible performance optimization). + */ + static final native Class loadClass(String name, boolean resolve) + throws ClassNotFoundException; + + /** + * Helper to load a resource from the bootstrap class loader. + * + * In libgcj, this does nothing, as the default system loader knows + * how to find resources that have been linked in. + * + * @param name the resource to find + * @return the URL to the resource + */ + static URL getResource(String name) + { + if (bootLoader != null) + return bootLoader.bootGetResource(name); + return null; + } + + /** + * Helper to get a list of resources from the bootstrap class loader. + * + * In libgcj, this does nothing, as the default system loader knows + * how to find resources that have been linked in. + * + * @param name the resource to find + * @return an enumeration of resources + * @throws IOException if one occurs + */ + static Enumeration getResources(String name) throws IOException + { + if (bootLoader != null) + return bootLoader.bootGetResources(name); + return EmptyEnumeration.getInstance(); + } + + /** + * Helper to get a package from the bootstrap class loader. The default + * implementation of returning null may be adequate, or you may decide + * that this needs some native help. + * + * @param name the name to find + * @return the named package, if it exists + */ + static synchronized Package getPackage(String name) + { + return (Package) definedPackages.get(name); + } + + /** + * Helper to get all packages from the bootstrap class loader. The default + * implementation of returning an empty array may be adequate, or you may + * decide that this needs some native help. + * + * @return all named packages, if any exist + */ + static synchronized Package[] getPackages() + { + Package[] packages = new Package[definedPackages.size()]; + return (Package[]) definedPackages.values().toArray(packages); + } + + // Define a package for something loaded natively. + static synchronized void definePackageForNative(String className) + { + int lastDot = className.lastIndexOf('.'); + if (lastDot != -1) + { + String packageName = className.substring(0, lastDot); + if (getPackage(packageName) == null) + { + // FIXME: this assumes we're defining the core, which + // isn't necessarily so. We could detect this and set up + // appropriately. We could also look at a manifest file + // compiled into the .so. + Package p = new Package(packageName, + "Java Platform API Specification", + "GNU", "1.4", "gcj", "GNU", + null, // FIXME: gcj version. + null); + definedPackages.put(packageName, p); + } + } + } + + /** + * Helper for java.lang.Integer, Byte, etc to get the TYPE class + * at initialization time. The type code is one of the chars that + * represents the primitive type as in JNI. + * + * <ul> + * <li>'Z' - boolean</li> + * <li>'B' - byte</li> + * <li>'C' - char</li> + * <li>'D' - double</li> + * <li>'F' - float</li> + * <li>'I' - int</li> + * <li>'J' - long</li> + * <li>'S' - short</li> + * <li>'V' - void</li> + * </ul> + * + * @param type the primitive type + * @return a "bogus" class representing the primitive type + */ + static final native Class getPrimitiveClass(char type); + + /** + * The system default for assertion status. This is used for all system + * classes (those with a null ClassLoader), as well as the initial value for + * every ClassLoader's default assertion status. + * + * XXX - Not implemented yet; this requires native help. + * + * @return the system-wide default assertion status + */ + static final boolean defaultAssertionStatus() + { + return true; + } + + /** + * The system default for package assertion status. This is used for all + * ClassLoader's packageAssertionStatus defaults. It must be a map of + * package names to Boolean.TRUE or Boolean.FALSE, with the unnamed package + * represented as a null key. + * + * XXX - Not implemented yet; this requires native help. + * + * @return a (read-only) map for the default packageAssertionStatus + */ + static final Map packageAssertionStatus() + { + return new HashMap(); + } + + /** + * The system default for class assertion status. This is used for all + * ClassLoader's classAssertionStatus defaults. It must be a map of + * class names to Boolean.TRUE or Boolean.FALSE + * + * XXX - Not implemented yet; this requires native help. + * + * @return a (read-only) map for the default classAssertionStatus + */ + static final Map classAssertionStatus() + { + return new HashMap(); + } + + static native ClassLoader getSystemClassLoaderInternal(); + + static native void initBootLoader(String libdir); + + static void initialize(String libdir) + { + initBootLoader(libdir); + + String p + = System.getProperty ("gnu.gcj.runtime.VMClassLoader.library_control", + ""); + if ("never".equals(p)) + lib_control = LIB_NEVER; + else if ("cache".equals(p)) + lib_control = LIB_CACHE; + else if ("full".equals(p)) + lib_control = LIB_FULL; + else + lib_control = LIB_NEVER; + + tried_libraries = new HashSet(); + } + + /** + * Possibly load a .so and search it for classes. + */ + static native Class nativeFindClass(String name); + + static ClassLoader getSystemClassLoader() + { + // This method is called as the initialization of systemClassLoader, + // so if there is a null value, this is the first call and we must check + // for java.system.class.loader. + String loader = System.getProperty("java.system.class.loader"); + ClassLoader default_sys = getSystemClassLoaderInternal(); + if (loader != null) + { + try + { + Class load_class = Class.forName(loader, true, default_sys); + Constructor c + = load_class.getConstructor(new Class[] { ClassLoader.class }); + default_sys + = (ClassLoader) c.newInstance(new Object[] { default_sys }); + } + catch (Exception ex) + { + throw new Error("Failed to load requested system classloader " + + loader, ex); + } + } + + return default_sys; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/VMCompiler.java b/gcc-4.2.1/libjava/java/lang/VMCompiler.java new file mode 100644 index 000000000..789445e4f --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/VMCompiler.java @@ -0,0 +1,360 @@ +/* VMClassLoader.java -- Reference implementation of compiler interface + Copyright (C) 2004, 2005, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStreamReader; +import java.security.MessageDigest; +import java.security.ProtectionDomain; +import java.security.NoSuchAlgorithmException; +import java.util.WeakHashMap; +import java.util.HashSet; +import java.util.Enumeration; +import java.util.StringTokenizer; +import java.util.Vector; +import gnu.gcj.runtime.SharedLibHelper; +import gnu.gcj.runtime.PersistentByteMap; +import gnu.java.security.hash.MD5; + +/** + * This class is just a per-VM reflection of java.lang.Compiler. + * All methods are defined identically. + */ +final class VMCompiler +{ + // True if we want to use gcj-jit. + public static boolean useCompiler = true; + + // True if we're able to use gcj-jit. + public static final boolean canUseCompiler; + + // Compiler to use. + public static String gcjJitCompiler; + + // Compiler options. + public static String gcjJitCompilerOptions; + + // Temporary directory to use. + public static String gcjJitTmpdir; + + // This maps a ClassLoader to a set of SharedLibHelper objects that + // it has used. We do things this way to ensure that a + // SharedLibHelper is collected if and only if the ClassLoader is. + private static WeakHashMap sharedHelperMap = new WeakHashMap(); + + private static Vector precompiledMapFiles; + + // We create a single MD5 engine and then clone it whenever we want + // a new one. + + // We don't use + // + // md5Digest = MessageDigest.getInstance("MD5"); + // + // here because that loads a great deal of security provider code as + // interpreted bytecode -- before we're able to use this class to + // load precompiled classes. + + private static final MD5 md5Digest + = new gnu.java.security.hash.MD5(); + + static + { + gcjJitCompiler = System.getProperty("gnu.gcj.jit.compiler"); + if (gcjJitCompiler == null) + canUseCompiler = false; + else + { + gcjJitCompilerOptions = System.getProperty("gnu.gcj.jit.options", + "-g"); + gcjJitTmpdir = System.getProperty("gnu.gcj.jit.cachedir"); + // Note that we *don't* choose java.io.tmpdir as a default -- + // that would allow easy attacks against the VM. + if (gcjJitTmpdir == null) + canUseCompiler = false; + else + canUseCompiler = true; + } + + String prop = System.getProperty ("gnu.gcj.precompiled.db.path"); + if (prop != null) + { + precompiledMapFiles = new Vector(); + // Add the + StringTokenizer st + = new StringTokenizer (prop, + System.getProperty ("path.separator", ":")); + { + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + PersistentByteMap map + = new PersistentByteMap + (e, PersistentByteMap.AccessMode.READ_ONLY); + precompiledMapFiles.add(map); + } + catch (IllegalArgumentException _) + { + // Not a map file + } + catch (java.io.IOException _) + { + } + catch (java.nio.BufferUnderflowException _) + { + // Invalid map file. + } + } + } + } + } + + /** + * Don't allow new `Compiler's to be made. + */ + private VMCompiler() + { + } + + private static Class loadSharedLibrary(ClassLoader loader, + String fileName, + ProtectionDomain domain, + String className) + { + Class c = null; + SharedLibHelper helper + = SharedLibHelper.findHelper (loader, fileName, domain.getCodeSource(), + domain, false); + c = helper.findClass (className); + if (c != null) + { + HashSet hs = (HashSet) sharedHelperMap.get(loader); + if (hs == null) + { + hs = new HashSet(); + sharedHelperMap.put(loader, hs); + } + hs.add(helper); + } + return c; + } + + /** + * Compile a class given the bytes for it. Returns the Class, or + * null if compilation failed or otherwise could not be done. + */ + public static Class compileClass(ClassLoader loader, + String name, byte[] data, + int offset, int len, + ProtectionDomain domain) + { + if (precompiledMapFiles == null + && (! useCompiler || ! canUseCompiler)) + return null; + + byte digest[]; + + try + { + MD5 md = (MD5) md5Digest.clone(); + md.update(data); + digest = md.digest(); + } + catch (NullPointerException _) + { + // If md5Digest==null -- but really this should never happen + // either, since the MD5 digest is in libgcj. + return null; + } + + // We use lookaside cache files to determine whether these bytes + // correspond to a class file that is part of a precompiled DSO. + if (precompiledMapFiles != null) + { + try + { + Enumeration elements = precompiledMapFiles.elements(); + while (elements.hasMoreElements()) + { + PersistentByteMap map = (PersistentByteMap)elements.nextElement(); + byte[] soName = map.get(digest); + if (soName != null) + return loadSharedLibrary(loader, + new String(soName), + domain, name); + } + } + catch (Exception _) + { + } + catch (UnknownError _) + { + // SharedLibHelper will throw UnknownError if the dlopen + // fails for some reason. We ignore it and continue on. + } + } + + if (! useCompiler || ! canUseCompiler) + return null; + + try + { + // FIXME: Make sure that the class represented by the + // bytes in DATA really is the class named in NAME. Make + // sure it's not "java.*". + StringBuffer hexBytes = new StringBuffer(gcjJitTmpdir); + hexBytes.append(File.separatorChar); + int digestLength = digest.length; + for (int i = 0; i < digestLength; ++i) + hexBytes.append(Integer.toHexString(digest[i] & 0xff)); + + // FIXME: use System.mapLibraryName? + // I'm thinking we should use that, plus a class specified + // via a property that determines lookup policy. + File soFile = new File(hexBytes + ".so"); + if (soFile.isFile()) + return loadSharedLibrary (loader, soFile.toString(), domain, + name); + + File classFile = new File(hexBytes + ".class"); + classFile.delete(); + if (classFile.createNewFile() != true) + return null; + + FileOutputStream f = new FileOutputStream (classFile); + // FIXME: race condition if bytes change... ? + f.write(data, offset, len); + + // Invoke the compiler. + StringBuffer command = new StringBuffer(gcjJitCompiler); + command.append(" "); + command.append(classFile); + command.append(" "); + command.append(gcjJitCompilerOptions); + // These options are required. + command.append(" -findirect-dispatch -fjni -shared -fPIC -o "); + command.append(soFile); + Process p = Runtime.getRuntime().exec(command.toString()); + + // Read the process' stderr into a string. + StringBuffer err = new StringBuffer(); + InputStreamReader stderr = new InputStreamReader (p.getErrorStream()); + char[] inBuf = new char[500]; + int bytesRead; + while ((bytesRead = stderr.read (inBuf)) != -1) + err.append(inBuf, 0, bytesRead); + + if (p.waitFor() != 0) + { + // FIXME: we could log err.toString() somewhere... + return null; + } + + return loadSharedLibrary(loader, soFile.toString(), domain, name); + } + catch (Exception _) + { + return null; + } + } + + /** + * Compile the class named by <code>oneClass</code>. + * + * @param oneClass the class to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if oneClass is null + */ + public static boolean compileClass(Class oneClass) + { + // Never succeed. + return false; + } + + /** + * Compile the classes whose name matches <code>classNames</code>. + * + * @param classNames the name of classes to compile + * @return <code>false</code> if no compiler is available or + * compilation failed, <code>true</code> if compilation succeeded + * @throws NullPointerException if classNames is null + */ + public static boolean compileClasses(String classNames) + { + // Note the incredibly lame interface. Always fail. + return false; + } + + /** + * This method examines the argument and performs an operation + * according to the compilers documentation. No specific operation + * is required. + * + * @param arg a compiler-specific argument + * @return a compiler-specific value, including null + * @throws NullPointerException if the compiler doesn't like a null arg + */ + public static Object command(Object arg) + { + // Our implementation defines this to a no-op. + return null; + } + + /** + * Calling <code>Compiler.enable()</code> will cause the compiler + * to resume operation if it was previously disabled; provided that a + * compiler even exists. + */ + public static void enable() + { + useCompiler = true; + } + + /** + * Calling <code>Compiler.disable()</code> will cause the compiler + * to be suspended; provided that a compiler even exists. + */ + public static void disable() + { + useCompiler = false; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/VMDouble.java b/gcc-4.2.1/libjava/java/lang/VMDouble.java new file mode 100644 index 000000000..9205eb3b3 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/VMDouble.java @@ -0,0 +1,111 @@ +/* VMDouble.java -- VM Specific Double methods + Copyright (C) 2003, 2005, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import gnu.classpath.Configuration; + +/* + * This class is a reference version, mainly for compiling a class library + * jar. It is likely that VM implementers replace this with their own + * version that can communicate effectively with the VM. + */ + +/** + * Code relocated from java.lang.Double by + * @author Dave Grove (groved@us.ibm.com) + */ +final class VMDouble +{ + /** + * Convert the double to the IEEE 754 floating-point "double format" bit + * layout. Bit 63 (the most significant) is the sign bit, bits 62-52 + * (masked by 0x7ff0000000000000L) represent the exponent, and bits 51-0 + * (masked by 0x000fffffffffffffL) are the mantissa. This function + * collapses all versions of NaN to 0x7ff8000000000000L. The result of this + * function can be used as the argument to + * <code>Double.longBitsToDouble(long)</code> to obtain the original + * <code>double</code> value. + * + * @param value the <code>double</code> to convert + * @return the bits of the <code>double</code> + * @see #longBitsToDouble(long) + */ + public static native long doubleToLongBits(double value); + + /** + * Convert the double to the IEEE 754 floating-point "double format" bit + * layout. Bit 63 (the most significant) is the sign bit, bits 62-52 + * (masked by 0x7ff0000000000000L) represent the exponent, and bits 51-0 + * (masked by 0x000fffffffffffffL) are the mantissa. This function + * leaves NaN alone, rather than collapsing to a canonical value. The + * result of this function can be used as the argument to + * <code>Double.longBitsToDouble(long)</code> to obtain the original + * <code>double</code> value. + * + * @param value the <code>double</code> to convert + * @return the bits of the <code>double</code> + * @see #longBitsToDouble(long) + */ + public static native long doubleToRawLongBits(double value); + + /** + * Convert the argument in IEEE 754 floating-point "double format" bit + * layout to the corresponding float. Bit 63 (the most significant) is the + * sign bit, bits 62-52 (masked by 0x7ff0000000000000L) represent the + * exponent, and bits 51-0 (masked by 0x000fffffffffffffL) are the mantissa. + * This function leaves NaN alone, so that you can recover the bit pattern + * with <code>Double.doubleToRawLongBits(double)</code>. + * + * @param bits the bits to convert + * @return the <code>double</code> represented by the bits + * @see #doubleToLongBits(double) + * @see #doubleToRawLongBits(double) + */ + public static native double longBitsToDouble(long bits); + + /** + * Helper method to convert to string. + * + * @param d the double to convert + * @param isFloat true if the conversion is requested by Float (results in + * fewer digits) + */ + public static native String toString(double d, boolean isFloat); + + public static native double parseDouble(String str); +} diff --git a/gcc-4.2.1/libjava/java/lang/VMFloat.java b/gcc-4.2.1/libjava/java/lang/VMFloat.java new file mode 100644 index 000000000..a6570f929 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/VMFloat.java @@ -0,0 +1,99 @@ +/* VMFloat.java -- VM Specific Float methods + Copyright (C) 2003, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import gnu.classpath.Configuration; + +/* + * This class is a reference version, mainly for compiling a class library + * jar. It is likely that VM implementers replace this with their own + * version that can communicate effectively with the VM. + */ + +/** + * Code relocated from java.lang.Float by + * @author Dave Grove <groved@us.ibm.com> + */ +final class VMFloat +{ + /** + * Convert the float to the IEEE 754 floating-point "single format" bit + * layout. Bit 31 (the most significant) is the sign bit, bits 30-23 + * (masked by 0x7f800000) represent the exponent, and bits 22-0 + * (masked by 0x007fffff) are the mantissa. This function collapses all + * versions of NaN to 0x7fc00000. The result of this function can be used + * as the argument to <code>Float.intBitsToFloat(int)</code> to obtain the + * original <code>float</code> value. + * + * @param value the <code>float</code> to convert + * @return the bits of the <code>float</code> + * @see #intBitsToFloat(int) + */ + static native int floatToIntBits(float value); + + /** + * Convert the float to the IEEE 754 floating-point "single format" bit + * layout. Bit 31 (the most significant) is the sign bit, bits 30-23 + * (masked by 0x7f800000) represent the exponent, and bits 22-0 + * (masked by 0x007fffff) are the mantissa. This function leaves NaN alone, + * rather than collapsing to a canonical value. The result of this function + * can be used as the argument to <code>Float.intBitsToFloat(int)</code> to + * obtain the original <code>float</code> value. + * + * @param value the <code>float</code> to convert + * @return the bits of the <code>float</code> + * @see #intBitsToFloat(int) + */ + static native int floatToRawIntBits(float value); + + /** + * Convert the argument in IEEE 754 floating-point "single format" bit + * layout to the corresponding float. Bit 31 (the most significant) is the + * sign bit, bits 30-23 (masked by 0x7f800000) represent the exponent, and + * bits 22-0 (masked by 0x007fffff) are the mantissa. This function leaves + * NaN alone, so that you can recover the bit pattern with + * <code>Float.floatToRawIntBits(float)</code>. + * + * @param bits the bits to convert + * @return the <code>float</code> represented by the bits + * @see #floatToIntBits(float) + * @see #floatToRawIntBits(float) + */ + static native float intBitsToFloat(int bits); + +} // class VMFloat diff --git a/gcc-4.2.1/libjava/java/lang/VMSecurityManager.java b/gcc-4.2.1/libjava/java/lang/VMSecurityManager.java new file mode 100644 index 000000000..25aeb7c49 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/VMSecurityManager.java @@ -0,0 +1,68 @@ +/* + * java.lang.SecurityManager: part of the Java Class Libraries project. + * Copyright (C) 1998, 2001, 2002, 2005 Free Software Foundation + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +package java.lang; + +import java.net.*; +import java.util.*; +import java.io.*; + +/** + ** VMSecurityManager is a helper class for SecurityManager the VM must + ** implement. + ** + ** @author John Keiser + ** @version 1.1.0, 31 May 1998 + **/ +class VMSecurityManager +{ + /** Get a list of all the classes currently executing + ** methods on the Java stack. getClassContext()[0] is + ** the currently executing method + ** <STRONG>Spec Note:</STRONG> does not say whether + ** the stack will include the getClassContext() call or + ** the one just before it. + ** + ** @return an array containing all the methods on classes + ** on the Java execution stack. + **/ + static native Class[] getClassContext(Class caller); + + /** Get the current ClassLoader--the one nearest to the + ** top of the stack. + ** @return the current ClassLoader. + **/ + static ClassLoader currentClassLoader(Class caller) + { + // The docs above are wrong. See the online docs. + // FIXME this implementation is a bit wrong too -- the docs say we + // must also consider ancestors of the system class loader. + ClassLoader systemClassLoader = ClassLoader.systemClassLoader; + Class[] classStack = getClassContext (caller); + for (int i = 0; i < classStack.length; i++) + { + ClassLoader loader = classStack[i].getClassLoader(); + if (loader != null && loader != systemClassLoader) + return loader; + } + + return null; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/VMThrowable.java b/gcc-4.2.1/libjava/java/lang/VMThrowable.java new file mode 100644 index 000000000..9dde28d29 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/VMThrowable.java @@ -0,0 +1,82 @@ +/* java.lang.VMThrowable -- VM support methods for Throwable. + Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang; + +import gnu.gcj.RawDataManaged; + +/** + * VM dependent state and support methods Throwable. + * It is deliberately package local and final and should only be accessed + * by the Throwable class. + * <p> + * This is the version used by libgcj (http://gcc.gnu.org/java/). + * + * @author Mark Wielaard (mark@klomp.org) + */ +final class VMThrowable +{ + /** + * Private contructor, create VMThrowables with StackTrace(); + */ + private VMThrowable() { } + + /** + * Fill in the stack trace with the current execution stack. + * Called by <code>Throwable.fillInStackTrace()</code> to get the state of + * the VM. Can return null when the VM does not support caputing the VM + * execution state. + * + * @return a new VMThrowable containing the current execution stack trace. + * @see Throwable#fillInStackTrace() + */ + static native VMThrowable fillInStackTrace(Throwable t); + + /** + * Returns an <code>StackTraceElement</code> array based on the execution + * state of the VM as captured by <code>fillInStackTrace</code>. + * Called by <code>Throwable.getStackTrace()</code>. + * + * @return a non-null but possible zero length array of StackTraceElement. + * @see Throwable#getStackTrace() + */ + native StackTraceElement[] getStackTrace(Throwable t); + + // Native stack data. + private RawDataManaged data; +} diff --git a/gcc-4.2.1/libjava/java/lang/Win32Process.java b/gcc-4.2.1/libjava/java/lang/Win32Process.java new file mode 100644 index 000000000..b0ef487c2 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/Win32Process.java @@ -0,0 +1,90 @@ +// Win32Process.java - Subclass of Process for Win32 systems. + +/* Copyright (C) 2002, 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang; + +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.IOException; + +/** + * @author Adam Megacz + * @date Feb 24, 2002 + */ + +// This is entirely internal to our implementation. + +// This file is copied to `ConcreteProcess.java' before compilation. +// Hence the class name apparently does not match the file name. +final class ConcreteProcess extends Process +{ + public native void destroy (); + + public int exitValue () + { + if (! hasExited ()) + throw new IllegalThreadStateException ("Process has not exited"); + + return exitCode; + } + + public InputStream getErrorStream () + { + return errorStream; + } + + public InputStream getInputStream () + { + return inputStream; + } + + public OutputStream getOutputStream () + { + return outputStream; + } + + public native int waitFor () throws InterruptedException; + + public ConcreteProcess (String[] progarray, + String[] envp, + File dir) + throws IOException + { + for (int i = 0; i < progarray.length; i++) + { + String s = progarray[i]; + + if ( (s.indexOf (' ') >= 0) || (s.indexOf ('\t') >= 0)) + progarray[i] = "\"" + s + "\""; + } + + startProcess (progarray, envp, dir); + } + + // The standard streams (stdin, stdout and stderr, respectively) + // of the child as seen by the parent process. + private OutputStream outputStream; + private InputStream inputStream; + private InputStream errorStream; + + // Handle to the child process - cast to HANDLE before use. + private int procHandle; + + // Exit code of the child if it has exited. + private int exitCode; + + private native boolean hasExited (); + private native void startProcess (String[] progarray, + String[] envp, + File dir) + throws IOException; + private native void cleanup (); +} diff --git a/gcc-4.2.1/libjava/java/lang/management/VMManagementFactory.java b/gcc-4.2.1/libjava/java/lang/management/VMManagementFactory.java new file mode 100644 index 000000000..6a906c730 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/management/VMManagementFactory.java @@ -0,0 +1,84 @@ +/* VMManagementFactory.java - VM interface for obtaining system beans. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.management; + +/** + * Provides lists of resources required by the + * {@link java.lang.management.ManagementFactory} for + * creating beans. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +final class VMManagementFactory +{ + + /** + * Return a list of the names of the currently available + * memory pools within the virtual machine. + * + * @return a list of memory pool names. + */ + static String[] getMemoryPoolNames() + { + return new String[0]; + } + + /** + * Return a list of the names of the currently available + * memory managers within the virtual machine. This should + * not include the garbage collectors listed below. + * + * @return a list of memory manager names. + */ + static String[] getMemoryManagerNames() + { + return new String[0]; + } + + /** + * Return a list of the names of the currently available + * garbage collectors within the virtual machine. + * + * @return a list of garbage collector names. + */ + static String[] getGarbageCollectorNames() + { + return new String[0]; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/natCharacter.cc b/gcc-4.2.1/libjava/java/lang/natCharacter.cc new file mode 100644 index 000000000..8d246dd56 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natCharacter.cc @@ -0,0 +1,237 @@ +/* java.lang.Character -- Wrapper class for char, and Unicode subsets + Copyright (C) 1998, 1999, 2001, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/Character.h> + +#include <java-chartables.h> + + + +// These constants define the return values for characters that are unassigned +// or reserved for private use. +#define UNASSIGNED_TYPE 0 +#define UNASSIGNED_DIGIT -1 +#define UNASSIGNED_DIRECTION -1 +#define UNASSIGNED_NUMERIC_VALUE -1 + +#define PRIVATE_TYPE 18 +#define PRIVATE_DIRECTION 0 + +// The methods that take a char as an argument all have counterparts that +// take ints. The ones that take chars only work for the BMP or plane 0 of the +// Unicode standard but the ones that take ints work for all Unicode code +// points. However, the ones that take chars don't simply redirect the calls +// because the BMP is by far the most used plane so saving a little time on +// each call makes sense. + +jchar +java::lang::Character::readChar(jchar ch) +{ + // Perform 16-bit addition to find the correct entry in data. + return data[0][(jchar) (blocks[0][ch >> shift[0]] + ch)]; +} + +jchar +java::lang::Character::readCodePoint(jint codePoint) +{ + jint plane = codePoint >> 16; + jchar offset = (jchar)(codePoint & 0xffff); + // Be careful not to call this method with an unassigned character. The only + // characters assigned as of Unicode 4.0.0 belong to planes 0, 1, 2, and 14. + return data[plane][(jchar) (blocks[plane][offset >> shift[plane]] + offset)]; +} + +jint +java::lang::Character::getType(jchar ch) +{ + // Perform 16-bit addition to find the correct entry in data. + return (jint) (data[0][(jchar) (blocks[0][ch >> shift[0]] + ch)] & TYPE_MASK); +} + +jint +java::lang::Character::getType(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane > 2 && plane != 14) + { + if (plane > 14 && ((codePoint & 0xffff) < 0xfffe)) + return (jint) PRIVATE_TYPE; + return (jint) UNASSIGNED_TYPE; + } + jint offset = codePoint & 0xffff; + return (jint) + (data[plane] + [(jchar) (blocks[plane][offset >> shift[plane]] + offset)] & TYPE_MASK); +} + +jchar +java::lang::Character::toLowerCase(jchar ch) +{ + return (jchar) (ch + lower[0][readChar(ch) >> 7]); +} + +jint +java::lang::Character::toLowerCase(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane > 2 && plane != 14) + return codePoint; + return (lower[plane][readCodePoint(codePoint) >> 7]) + codePoint; +} + +jchar +java::lang::Character::toUpperCase(jchar ch) +{ + return (jchar) (ch + upper[0][readChar(ch) >> 7]); +} + +jint +java::lang::Character::toUpperCase(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane > 2 && plane != 14) + return codePoint; + return (upper[plane][readCodePoint(codePoint) >> 7]) + codePoint; +} + +jchar +java::lang::Character::toTitleCase(jchar ch) +{ + // As title is short, it doesn't hurt to exhaustively iterate over it. + for (int i = title_length - 2; i >= 0; i -= 2) + if (title[i] == ch) + return title[i + 1]; + return toUpperCase(ch); +} + +jint +java::lang::Character::toTitleCase(jint codePoint) +{ + // As of Unicode 4.0.0 no characters outside of plane 0 have titlecase + // mappings that are different from their uppercase mapping. + if (codePoint < 0x10000) + return toTitleCase((jchar)codePoint); + return toUpperCase(codePoint); +} + +jint +java::lang::Character::digit(jchar ch, jint radix) +{ + if (radix < MIN_RADIX || radix > MAX_RADIX) + return (jint) -1; + jchar attr = readChar(ch); + if (((1 << (attr & TYPE_MASK)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER)))) + { + // Signedness doesn't matter; 0xffff vs. -1 are both rejected. + jint digit = (jint) numValue[0][attr >> 7]; + return (digit >= 0 && digit < radix) ? digit : (jint) -1; + } + return (jint) -1; +} + +jint +java::lang::Character::digit(jint codePoint, jint radix) +{ + if (radix < MIN_RADIX || radix > MAX_RADIX) + return (jint) -1; + + jint plane = codePoint >> 16; + if (plane > 2 && plane != 14) + return UNASSIGNED_DIGIT; + + jchar attr = readCodePoint(codePoint); + if (((1 << (attr & TYPE_MASK)) + & ((1 << UPPERCASE_LETTER) + | (1 << LOWERCASE_LETTER) + | (1 << DECIMAL_DIGIT_NUMBER)))) + { + // Signedness doesn't matter; 0xffff vs. -1 are both rejected. + jint digit = (jint) numValue[plane][attr >> 7]; + if (digit <= -3) + digit = largenums[-digit -3]; + return (digit >= 0 && digit < radix) ? digit : (jint) -1; + } + return (jint) -1; + +} + +jint +java::lang::Character::getNumericValue(jchar ch) +{ + // numValue is stored as an array of jshort, since 10000 is the maximum. + return (jint) numValue[0][readChar(ch) >> 7]; +} + +jint +java::lang::Character::getNumericValue(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane > 2 && plane != 14) + return UNASSIGNED_NUMERIC_VALUE; + jshort num = numValue[plane][readCodePoint(codePoint) >> 7]; + if (num <= -3) + return largenums[-num - 3]; + return num; +} + +jbyte +java::lang::Character::getDirectionality(jchar ch) +{ + return direction[0][readChar(ch) >> 7]; +} + +jbyte +java::lang::Character::getDirectionality(jint codePoint) +{ + jint plane = codePoint >> 16; + if (plane > 2 && plane != 14) + { + if (plane > 14 && ((codePoint & 0xffff) < 0xfffe)) + return (jint) PRIVATE_DIRECTION; + return (jint) UNASSIGNED_DIRECTION; + } + return direction[plane][readCodePoint(codePoint) >> 7]; +} + + diff --git a/gcc-4.2.1/libjava/java/lang/natClass.cc b/gcc-4.2.1/libjava/java/lang/natClass.cc new file mode 100644 index 000000000..12984291e --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natClass.cc @@ -0,0 +1,1269 @@ +// natClass.cc - Implementation of java.lang.Class native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <limits.h> +#include <string.h> +#include <stddef.h> +#include <stdio.h> + +#pragma implementation "Class.h" + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-threads.h> + +#include <java/lang/Class.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/String.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/reflect/Member.h> +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/Field.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/AbstractMethodError.h> +#include <java/lang/ArrayStoreException.h> +#include <java/lang/ClassCastException.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/ExceptionInInitializerError.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/IllegalAccessError.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/NoSuchFieldError.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/InstantiationException.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/NoSuchFieldException.h> +#include <java/lang/NoSuchMethodError.h> +#include <java/lang/NoSuchMethodException.h> +#include <java/lang/Thread.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/RuntimePermission.h> +#include <java/lang/System.h> +#include <java/lang/SecurityManager.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/VMClassLoader.h> +#include <gcj/method.h> +#include <gnu/gcj/RawData.h> +#include <java/lang/VerifyError.h> + +#include <java-cpool.h> +#include <java-interp.h> +#include <java-assert.h> +#include <java-stack.h> +#include <execution.h> + + + +using namespace gcj; + +jclass +java::lang::Class::forName (jstring className, jboolean initialize, + java::lang::ClassLoader *loader) +{ + if (! className) + throw new java::lang::NullPointerException; + + jsize length = _Jv_GetStringUTFLength (className); + char buffer[length]; + _Jv_GetStringUTFRegion (className, 0, className->length(), buffer); + + _Jv_Utf8Const *name = _Jv_makeUtf8Const (buffer, length); + + if (! _Jv_VerifyClassName (name)) + throw new java::lang::ClassNotFoundException (className); + + jclass klass = (buffer[0] == '[' + ? _Jv_FindClassFromSignature (name->chars(), loader) + : _Jv_FindClass (name, loader)); + + if (klass == NULL) + throw new java::lang::ClassNotFoundException (className); + + if (initialize) + _Jv_InitClass (klass); + + return klass; +} + +jclass +java::lang::Class::forName (jstring className) +{ + java::lang::ClassLoader *loader = NULL; + + jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$); + if (caller) + loader = caller->getClassLoaderInternal(); + + return forName (className, true, loader); +} + +java::lang::ClassLoader * +java::lang::Class::getClassLoader (void) +{ + java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); + if (s != NULL) + { + jclass caller = _Jv_StackTrace::GetCallingClass (&Class::class$); + return getClassLoader (caller); + } + + return loader; +} + +java::lang::ClassLoader * +java::lang::Class::getClassLoader (jclass caller) +{ + java::lang::SecurityManager *s = java::lang::System::getSecurityManager(); + if (s != NULL) + { + ClassLoader *caller_loader = caller->getClassLoaderInternal(); + + // If the caller has a non-null class loader, and that loader + // is not this class' loader or an ancestor thereof, then do a + // security check. + if (caller_loader != NULL && ! caller_loader->isAncestorOf(loader)) + s->checkPermission (new RuntimePermission (JvNewStringLatin1 ("getClassLoader"))); + } + + return loader; +} + +java::lang::reflect::Constructor * +java::lang::Class::getConstructor (JArray<jclass> *param_types) +{ + memberAccessCheck(java::lang::reflect::Member::PUBLIC); + + jstring partial_sig = getSignature (param_types, true); + jint hash = partial_sig->hashCode (); + + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (methods[i].name, init_name) + && _Jv_equal (methods[i].signature, partial_sig, hash)) + { + // Found it. For getConstructor, the constructor must be + // public. + using namespace java::lang::reflect; + if (! Modifier::isPublic(methods[i].accflags)) + break; + Constructor *cons = new Constructor (); + cons->offset = (char *) (&methods[i]) - (char *) methods; + cons->declaringClass = this; + return cons; + } + } + throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name)); +} + +JArray<java::lang::reflect::Constructor *> * +java::lang::Class::getDeclaredConstructors (jboolean publicOnly) +{ + int numConstructors = 0; + int max = isPrimitive () ? 0 : method_count; + int i; + for (i = max; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || ! _Jv_equalUtf8Consts (method->name, init_name)) + continue; + if (publicOnly + && ! java::lang::reflect::Modifier::isPublic(method->accflags)) + continue; + numConstructors++; + } + JArray<java::lang::reflect::Constructor *> *result + = (JArray<java::lang::reflect::Constructor *> *) + JvNewObjectArray (numConstructors, + &java::lang::reflect::Constructor::class$, + NULL); + java::lang::reflect::Constructor** cptr = elements (result); + for (i = 0; i < max; i++) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || ! _Jv_equalUtf8Consts (method->name, init_name)) + continue; + if (publicOnly + && ! java::lang::reflect::Modifier::isPublic(method->accflags)) + continue; + java::lang::reflect::Constructor *cons + = new java::lang::reflect::Constructor (); + cons->offset = (char *) method - (char *) methods; + cons->declaringClass = this; + *cptr++ = cons; + } + return result; +} + +java::lang::reflect::Constructor * +java::lang::Class::getDeclaredConstructor (JArray<jclass> *param_types) +{ + memberAccessCheck(java::lang::reflect::Member::DECLARED); + + jstring partial_sig = getSignature (param_types, true); + jint hash = partial_sig->hashCode (); + + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (methods[i].name, init_name) + && _Jv_equal (methods[i].signature, partial_sig, hash)) + { + // Found it. + using namespace java::lang::reflect; + Constructor *cons = new Constructor (); + cons->offset = (char *) (&methods[i]) - (char *) methods; + cons->declaringClass = this; + return cons; + } + } + throw new java::lang::NoSuchMethodException (_Jv_NewStringUtf8Const (init_name)); +} + +java::lang::reflect::Field * +java::lang::Class::getField (jstring name, jint hash) +{ + java::lang::reflect::Field* rfield; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + if (! (field->getModifiers() & java::lang::reflect::Modifier::PUBLIC)) + continue; + rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + jclass superclass = getSuperclass(); + if (superclass == NULL) + return NULL; + rfield = superclass->getField(name, hash); + for (int i = 0; i < interface_count && rfield == NULL; ++i) + rfield = interfaces[i]->getField (name, hash); + return rfield; +} + +java::lang::reflect::Field * +java::lang::Class::getDeclaredField (jstring name) +{ + memberAccessCheck(java::lang::reflect::Member::DECLARED); + int hash = name->hashCode(); + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + java::lang::reflect::Field* rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + throw new java::lang::NoSuchFieldException (name); +} + +JArray<java::lang::reflect::Field *> * +java::lang::Class::getDeclaredFields (jboolean public_only) +{ + int size; + if (public_only) + { + size = 0; + for (int i = 0; i < field_count; ++i) + { + _Jv_Field *field = &fields[i]; + if ((field->flags & java::lang::reflect::Modifier::PUBLIC)) + ++size; + } + } + else + size = field_count; + + JArray<java::lang::reflect::Field *> *result + = (JArray<java::lang::reflect::Field *> *) + JvNewObjectArray (size, &java::lang::reflect::Field::class$, NULL); + java::lang::reflect::Field** fptr = elements (result); + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (public_only + && ! (field->flags & java::lang::reflect::Modifier::PUBLIC)) + continue; + java::lang::reflect::Field* rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + *fptr++ = rfield; + } + return result; +} + +void +java::lang::Class::getSignature (java::lang::StringBuffer *buffer) +{ + if (isPrimitive()) + buffer->append((jchar) method_count); + else + { + jstring name = getName(); + if (name->charAt(0) != '[') + buffer->append((jchar) 'L'); + buffer->append(name); + if (name->charAt(0) != '[') + buffer->append((jchar) ';'); + } +} + +// This doesn't have to be native. It is an implementation detail +// only called from the C++ code, though, so maybe this is clearer. +jstring +java::lang::Class::getSignature (JArray<jclass> *param_types, + jboolean is_constructor) +{ + java::lang::StringBuffer *buf = new java::lang::StringBuffer (); + buf->append((jchar) '('); + // A NULL param_types means "no parameters". + if (param_types != NULL) + { + jclass *v = elements (param_types); + for (int i = 0; i < param_types->length; ++i) + v[i]->getSignature(buf); + } + buf->append((jchar) ')'); + if (is_constructor) + buf->append((jchar) 'V'); + return buf->toString(); +} + +java::lang::reflect::Method * +java::lang::Class::_getDeclaredMethod (jstring name, + JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + int i = isPrimitive () ? 0 : method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (methods[i].name, utf_name) + && _Jv_equaln (methods[i].signature, partial_sig, p_len) + && (methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) == 0) + { + // Found it. + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char*) (&methods[i]) - (char*) methods; + rmethod->declaringClass = this; + return rmethod; + } + } + return NULL; +} + +JArray<java::lang::reflect::Method *> * +java::lang::Class::getDeclaredMethods (void) +{ + memberAccessCheck(java::lang::reflect::Member::DECLARED); + + int numMethods = 0; + int max = isPrimitive () ? 0 : method_count; + int i; + for (i = max; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || _Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name) + || _Jv_equalUtf8Consts (method->name, finit_name) + || (methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) != 0) + continue; + numMethods++; + } + JArray<java::lang::reflect::Method *> *result + = (JArray<java::lang::reflect::Method *> *) + JvNewObjectArray (numMethods, &java::lang::reflect::Method::class$, NULL); + java::lang::reflect::Method** mptr = elements (result); + for (i = 0; i < max; i++) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || _Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name) + || _Jv_equalUtf8Consts (method->name, finit_name) + || (methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) != 0) + continue; + java::lang::reflect::Method* rmethod + = new java::lang::reflect::Method (); + rmethod->offset = (char*) method - (char*) methods; + rmethod->declaringClass = this; + *mptr++ = rmethod; + } + return result; +} + +jstring +java::lang::Class::getName (void) +{ + return name->toString(); +} + +JArray<jclass> * +java::lang::Class::getDeclaredClasses (jboolean /*publicOnly*/) +{ + // Until we have inner classes, it always makes sense to return an + // empty array. + JArray<jclass> *result + = (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$, + NULL); + return result; +} + +jclass +java::lang::Class::getDeclaringClass (void) +{ + // Until we have inner classes, it makes sense to always return + // NULL. + return NULL; +} + +JArray<jclass> * +java::lang::Class::getInterfaces (void) +{ + jobjectArray r = JvNewObjectArray (interface_count, getClass (), NULL); + jobject *data = elements (r); + for (int i = 0; i < interface_count; ++i) + { + typedef unsigned int uaddr __attribute__ ((mode (pointer))); + data[i] = interfaces[i]; + if ((uaddr)data[i] < (uaddr)constants.size) + fprintf (stderr, "ERROR !!!\n"); + } + return reinterpret_cast<JArray<jclass> *> (r); +} + +java::lang::reflect::Method * +java::lang::Class::_getMethod (jstring name, JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len) + && (klass->methods[i].accflags + & java::lang::reflect::Modifier::INVISIBLE) == 0) + { + // Found it. + using namespace java::lang::reflect; + + // Method must be public. + if (! Modifier::isPublic (klass->methods[i].accflags)) + break; + + Method *rmethod = new Method (); + rmethod->offset = ((char *) (&klass->methods[i]) + - (char *) klass->methods); + rmethod->declaringClass = klass; + return rmethod; + } + } + } + + // If we haven't found a match, and this class is an interface, then + // check all the superinterfaces. + if (isInterface()) + { + for (int i = 0; i < interface_count; ++i) + { + using namespace java::lang::reflect; + Method *rmethod = interfaces[i]->_getMethod (name, param_types); + if (rmethod != NULL) + return rmethod; + } + } + + return NULL; +} + +// This is a very slow implementation, since it re-scans all the +// methods we've already listed to make sure we haven't duplicated a +// method. It also over-estimates the required size, so we have to +// shrink the result array later. +jint +java::lang::Class::_getMethods (JArray<java::lang::reflect::Method *> *result, + jint offset) +{ + jint count = 0; + + // First examine all local methods + for (int i = isPrimitive () ? 0 : method_count; --i >= 0; ) + { + _Jv_Method *method = &methods[i]; + if (method->name == NULL + || _Jv_equalUtf8Consts (method->name, clinit_name) + || _Jv_equalUtf8Consts (method->name, init_name) + || _Jv_equalUtf8Consts (method->name, finit_name) + || (method->accflags + & java::lang::reflect::Modifier::INVISIBLE) != 0) + continue; + // Only want public methods. + if (! java::lang::reflect::Modifier::isPublic (method->accflags)) + continue; + + // This is where we over-count the slots required if we aren't + // filling the result for real. + if (result != NULL) + { + jboolean add = true; + java::lang::reflect::Method **mp = elements (result); + // If we already have a method with this name and signature, + // then ignore this one. This can happen with virtual + // methods. + for (int j = 0; j < offset; ++j) + { + _Jv_Method *meth_2 = _Jv_FromReflectedMethod (mp[j]); + if (_Jv_equalUtf8Consts (method->name, meth_2->name) + && _Jv_equalUtf8Consts (method->signature, + meth_2->signature)) + { + add = false; + break; + } + } + if (! add) + continue; + } + + if (result != NULL) + { + using namespace java::lang::reflect; + Method *rmethod = new Method (); + rmethod->offset = (char *) method - (char *) methods; + rmethod->declaringClass = this; + Method **mp = elements (result); + mp[offset + count] = rmethod; + } + ++count; + } + offset += count; + + // Now examine superclasses. + if (getSuperclass () != NULL) + { + jint s_count = getSuperclass()->_getMethods (result, offset); + offset += s_count; + count += s_count; + } + + // Finally, examine interfaces. + for (int i = 0; i < interface_count; ++i) + { + int f_count = interfaces[i]->_getMethods (result, offset); + count += f_count; + offset += f_count; + } + + return count; +} + +JArray<java::lang::reflect::Method *> * +java::lang::Class::getMethods (void) +{ + using namespace java::lang::reflect; + + memberAccessCheck(Member::PUBLIC); + + // This will overestimate the size we need. + jint count = _getMethods (NULL, 0); + + JArray<Method *> *result + = ((JArray<Method *> *) JvNewObjectArray (count, + &Method::class$, + NULL)); + + // When filling the array for real, we get the actual count. Then + // we resize the array. + jint real_count = _getMethods (result, 0); + + if (real_count != count) + { + JArray<Method *> *r2 + = ((JArray<Method *> *) JvNewObjectArray (real_count, + &Method::class$, + NULL)); + + Method **destp = elements (r2); + Method **srcp = elements (result); + + for (int i = 0; i < real_count; ++i) + *destp++ = *srcp++; + + result = r2; + } + + return result; +} + +jboolean +java::lang::Class::isAssignableFrom (jclass klass) +{ + // Arguments may not have been initialized, given ".class" syntax. + // This ensures we can at least look at their superclasses. + _Jv_Linker::wait_for_state (this, JV_STATE_LOADING); + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); + return _Jv_IsAssignableFrom (klass, this); +} + +jboolean +java::lang::Class::isInstance (jobject obj) +{ + if (! obj) + return false; + return _Jv_IsAssignableFrom (JV_CLASS (obj), this); +} + +jobject +java::lang::Class::newInstance (void) +{ + memberAccessCheck(java::lang::reflect::Member::PUBLIC); + + if (isPrimitive () + || isInterface () + || isArray () + || java::lang::reflect::Modifier::isAbstract(accflags)) + throw new java::lang::InstantiationException (getName ()); + + _Jv_InitClass (this); + + _Jv_Method *meth = _Jv_GetMethodLocal (this, init_name, void_signature); + if (! meth) + throw new java::lang::InstantiationException (getName()); + + jobject r = _Jv_AllocObject (this); + ((void (*) (jobject)) meth->ncode) (r); + return r; +} + +void +java::lang::Class::finalize (void) +{ + engine->unregister(this); +} + +// This implements the initialization process for a class. From Spec +// section 12.4.2. +void +java::lang::Class::initializeClass (void) +{ + // Short-circuit to avoid needless locking (expression includes + // JV_STATE_PHANTOM and JV_STATE_DONE). + if (state >= JV_STATE_PHANTOM) + return; + + // Step 1. We introduce a new scope so we can synchronize more + // easily. + { + JvSynchronize sync (this); + + if (state < JV_STATE_LINKED) + { + try + { + _Jv_Linker::wait_for_state(this, JV_STATE_LINKED); + } + catch (java::lang::Throwable *x) + { + // Turn into a NoClassDefFoundError. + java::lang::NoClassDefFoundError *result + = new java::lang::NoClassDefFoundError(getName()); + result->initCause(x); + throw result; + } + } + + // Step 2. + java::lang::Thread *self = java::lang::Thread::currentThread(); + self = (java::lang::Thread *) ((long) self | 1); + while (state == JV_STATE_IN_PROGRESS && thread && thread != self) + wait (); + + // Steps 3 & 4. + if (state == JV_STATE_DONE || state == JV_STATE_IN_PROGRESS) + return; + + // Step 5. + if (state == JV_STATE_ERROR) + throw new java::lang::NoClassDefFoundError (getName()); + + // Step 6. + thread = self; + _Jv_Linker::wait_for_state (this, JV_STATE_LINKED); + state = JV_STATE_IN_PROGRESS; + } + + // Step 7. + if (! isInterface () && superclass) + { + try + { + _Jv_InitClass (superclass); + } + catch (java::lang::Throwable *except) + { + // Caught an exception. + JvSynchronize sync (this); + state = JV_STATE_ERROR; + notifyAll (); + throw except; + } + } + + // Steps 8, 9, 10, 11. + try + { + _Jv_Method *meth = _Jv_GetMethodLocal (this, clinit_name, + void_signature); + if (meth) + ((void (*) (void)) meth->ncode) (); + } + catch (java::lang::Throwable *except) + { + if (! java::lang::Error::class$.isInstance(except)) + { + try + { + except = new ExceptionInInitializerError (except); + } + catch (java::lang::Throwable *t) + { + except = t; + } + } + + JvSynchronize sync (this); + state = JV_STATE_ERROR; + notifyAll (); + throw except; + } + + JvSynchronize sync (this); + state = JV_STATE_DONE; + notifyAll (); +} + +// Only used by serialization +java::lang::reflect::Field * +java::lang::Class::getPrivateField (jstring name) +{ + int hash = name->hashCode (); + + java::lang::reflect::Field* rfield; + for (int i = 0; i < field_count; i++) + { + _Jv_Field *field = &fields[i]; + if (! _Jv_equal (field->name, name, hash)) + continue; + rfield = new java::lang::reflect::Field (); + rfield->offset = (char*) field - (char*) fields; + rfield->declaringClass = this; + rfield->name = name; + return rfield; + } + jclass superclass = getSuperclass(); + if (superclass == NULL) + return NULL; + rfield = superclass->getPrivateField(name); + for (int i = 0; i < interface_count && rfield == NULL; ++i) + rfield = interfaces[i]->getPrivateField (name); + return rfield; +} + +// Only used by serialization +java::lang::reflect::Method * +java::lang::Class::getPrivateMethod (jstring name, JArray<jclass> *param_types) +{ + jstring partial_sig = getSignature (param_types, false); + jint p_len = partial_sig->length(); + _Jv_Utf8Const *utf_name = _Jv_makeUtf8Const (name); + for (Class *klass = this; klass; klass = klass->getSuperclass()) + { + int i = klass->isPrimitive () ? 0 : klass->method_count; + while (--i >= 0) + { + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equaln (klass->methods[i].signature, partial_sig, p_len)) + { + // Found it. + using namespace java::lang::reflect; + + Method *rmethod = new Method (); + rmethod->offset = ((char *) (&klass->methods[i]) + - (char *) klass->methods); + rmethod->declaringClass = klass; + return rmethod; + } + } + } + throw new java::lang::NoSuchMethodException (name); +} + +// Private accessor method for Java code to retrieve the protection domain. +java::security::ProtectionDomain * +java::lang::Class::getProtectionDomain0 () +{ + return protectionDomain; +} + +JArray<jobject> * +java::lang::Class::getSigners() +{ + return hack_signers; +} + +void +java::lang::Class::setSigners(JArray<jobject> *s) +{ + hack_signers = s; +} + + + +// +// Some class-related convenience functions. +// + +// Find a method declared in the class. If it is not declared locally +// (or if it is inherited), return NULL. +_Jv_Method * +_Jv_GetMethodLocal (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + for (int i = 0; i < klass->method_count; ++i) + { + if (_Jv_equalUtf8Consts (name, klass->methods[i].name) + && _Jv_equalUtf8Consts (signature, klass->methods[i].signature)) + return &klass->methods[i]; + } + return NULL; +} + +_Jv_Method * +_Jv_LookupDeclaredMethod (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature, + jclass *declarer_result) +{ + for (; klass; klass = klass->getSuperclass()) + { + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + + if (meth) + { + if (declarer_result) + *declarer_result = klass; + return meth; + } + } + + return NULL; +} + +#ifdef HAVE_TLS + +// NOTE: MCACHE_SIZE should be a power of 2 minus one. +#define MCACHE_SIZE 31 + +struct _Jv_mcache +{ + jclass klass; + _Jv_Method *method; +}; + +static __thread _Jv_mcache *method_cache; +#endif // HAVE_TLS + +static void * +_Jv_FindMethodInCache (jclass klass MAYBE_UNUSED, + _Jv_Utf8Const *name MAYBE_UNUSED, + _Jv_Utf8Const *signature MAYBE_UNUSED) +{ +#ifdef HAVE_TLS + _Jv_mcache *cache = method_cache; + if (cache) + { + int index = name->hash16 () & MCACHE_SIZE; + _Jv_mcache *mc = &cache[index]; + _Jv_Method *m = mc->method; + + if (mc->klass == klass + && _Jv_equalUtf8Consts (m->name, name) + && _Jv_equalUtf8Consts (m->signature, signature)) + return mc->method->ncode; + } +#endif // HAVE_TLS + return NULL; +} + +static void +_Jv_AddMethodToCache (jclass klass MAYBE_UNUSED, + _Jv_Method *method MAYBE_UNUSED) +{ +#ifdef HAVE_TLS + if (method_cache == NULL) + method_cache = (_Jv_mcache *) _Jv_MallocUnchecked((MCACHE_SIZE + 1) + * sizeof (_Jv_mcache)); + // If the allocation failed, just keep going. + if (method_cache != NULL) + { + int index = method->name->hash16 () & MCACHE_SIZE; + method_cache[index].method = method; + method_cache[index].klass = klass; + } +#endif // HAVE_TLS +} + +// Free this thread's method cache. We explicitly manage this memory +// as the GC does not yet know how to scan TLS on all platforms. +void +_Jv_FreeMethodCache () +{ +#ifdef HAVE_TLS + if (method_cache != NULL) + { + _Jv_Free(method_cache); + method_cache = NULL; + } +#endif // HAVE_TLS +} + +void * +_Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name, + _Jv_Utf8Const *signature) +{ + using namespace java::lang::reflect; + + void *ncode = _Jv_FindMethodInCache (klass, name, signature); + if (ncode != 0) + return ncode; + + for (; klass; klass = klass->getSuperclass()) + { + _Jv_Method *meth = _Jv_GetMethodLocal (klass, name, signature); + if (! meth) + continue; + + if (Modifier::isStatic(meth->accflags)) + throw new java::lang::IncompatibleClassChangeError + (_Jv_GetMethodString (klass, meth)); + if (Modifier::isAbstract(meth->accflags)) + throw new java::lang::AbstractMethodError + (_Jv_GetMethodString (klass, meth)); + if (! Modifier::isPublic(meth->accflags)) + throw new java::lang::IllegalAccessError + (_Jv_GetMethodString (klass, meth)); + + _Jv_AddMethodToCache (klass, meth); + + return meth->ncode; + } + throw new java::lang::IncompatibleClassChangeError; +} + +// Fast interface method lookup by index. +void * +_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, int method_idx) +{ + _Jv_IDispatchTable *cldt = klass->idt; + int idx = iface->ioffsets[cldt->iindex] + method_idx; + return cldt->itable[idx]; +} + +jboolean +_Jv_IsAssignableFrom (jclass source, jclass target) +{ + if (source == target) + return true; + + // If target is array, so must source be. + while (target->isArray ()) + { + if (! source->isArray()) + return false; + target = target->getComponentType(); + source = source->getComponentType(); + } + + if (target->isInterface()) + { + // Abstract classes have no IDT, and IDTs provide no way to check + // two interfaces for assignability. + if (__builtin_expect + (source->idt == NULL || source->isInterface(), false)) + return _Jv_InterfaceAssignableFrom (source, target); + + _Jv_IDispatchTable *cl_idt = source->idt; + + if (__builtin_expect ((target->ioffsets == NULL), false)) + return false; // No class implementing TARGET has been loaded. + jshort cl_iindex = cl_idt->iindex; + if (cl_iindex < target->ioffsets[0]) + { + jshort offset = target->ioffsets[cl_iindex]; + if (offset != -1 && offset < cl_idt->itable_length + && cl_idt->itable[offset] == target) + return true; + } + return false; + } + + // Primitive TYPE classes are only assignable to themselves. + if (__builtin_expect (target->isPrimitive() || source->isPrimitive(), false)) + return false; + + if (target == &java::lang::Object::class$) + return true; + else if (source->ancestors == NULL || target->ancestors == NULL) + { + // We need this case when either SOURCE or TARGET has not has + // its constant-time tables prepared. + + // At this point we know that TARGET can't be Object, so it is + // safe to use that as the termination point. + while (source && source != &java::lang::Object::class$) + { + if (source == target) + return true; + source = source->getSuperclass(); + } + } + else if (source->depth >= target->depth + && source->ancestors[source->depth - target->depth] == target) + return true; + + return false; +} + +// Interface type checking, the slow way. Returns TRUE if IFACE is a +// superinterface of SOURCE. This is used when SOURCE is also an interface, +// or a class with no interface dispatch table. +jboolean +_Jv_InterfaceAssignableFrom (jclass source, jclass iface) +{ + for (int i = 0; i < source->interface_count; i++) + { + jclass interface = source->interfaces[i]; + if (iface == interface + || _Jv_InterfaceAssignableFrom (interface, iface)) + return true; + } + + if (!source->isInterface() + && source->superclass + && _Jv_InterfaceAssignableFrom (source->superclass, iface)) + return true; + + return false; +} + +jboolean +_Jv_IsInstanceOf(jobject obj, jclass cl) +{ + if (__builtin_expect (!obj, false)) + return false; + return _Jv_IsAssignableFrom (JV_CLASS (obj), cl); +} + +void * +_Jv_CheckCast (jclass c, jobject obj) +{ + if (__builtin_expect + (obj != NULL && ! _Jv_IsAssignableFrom(JV_CLASS (obj), c), false)) + throw new java::lang::ClassCastException + ((new java::lang::StringBuffer + (obj->getClass()->getName()))->append + (JvNewStringUTF(" cannot be cast to "))->append + (c->getName())->toString()); + + return obj; +} + +void +_Jv_CheckArrayStore (jobject arr, jobject obj) +{ + if (obj) + { + JvAssert (arr != NULL); + jclass elt_class = (JV_CLASS (arr))->getComponentType(); + if (elt_class == &java::lang::Object::class$) + return; + jclass obj_class = JV_CLASS (obj); + if (__builtin_expect + (! _Jv_IsAssignableFrom (obj_class, elt_class), false)) + throw new java::lang::ArrayStoreException + ((new java::lang::StringBuffer + (JvNewStringUTF("Cannot store ")))->append + (obj_class->getName())->append + (JvNewStringUTF(" in array of type "))->append + (elt_class->getName())->toString()); + } +} + +jboolean +_Jv_IsAssignableFromSlow (jclass source, jclass target) +{ + // First, strip arrays. + while (target->isArray ()) + { + // If target is array, source must be as well. + if (! source->isArray ()) + return false; + target = target->getComponentType (); + source = source->getComponentType (); + } + + // Quick success. + if (target == &java::lang::Object::class$) + return true; + + // Ensure that the classes have their supers installed. + _Jv_Linker::wait_for_state (source, JV_STATE_LOADING); + _Jv_Linker::wait_for_state (target, JV_STATE_LOADING); + + do + { + if (source == target) + return true; + + if (target->isPrimitive () || source->isPrimitive ()) + return false; + + if (target->isInterface ()) + { + for (int i = 0; i < source->interface_count; ++i) + { + // We use a recursive call because we also need to + // check superinterfaces. + if (_Jv_IsAssignableFromSlow (source->getInterface (i), target)) + return true; + } + } + source = source->getSuperclass (); + } + while (source != NULL); + + return false; +} + +// Lookup an interface method by name. This is very similar to +// purpose to _getMethod, but the interfaces are quite different. It +// might be a good idea for _getMethod to call this function. +// +// Return true of the method is found, with the class in FOUND_CLASS +// and the index in INDEX. +bool +_Jv_getInterfaceMethod (jclass search_class, jclass &found_class, int &index, + const _Jv_Utf8Const *utf_name, + const _Jv_Utf8Const *utf_sig) +{ + for (jclass klass = search_class; klass; klass = klass->getSuperclass()) + { + // FIXME: Throw an exception? + if (!klass->isInterface ()) + return false; + + int max = klass->method_count; + int offset = 0; + for (int i = 0; i < max; ++i) + { + // Skip <clinit> here, as it will not be in the IDT. + if (klass->methods[i].name->first() == '<') + continue; + + if (_Jv_equalUtf8Consts (klass->methods[i].name, utf_name) + && _Jv_equalUtf8Consts (klass->methods[i].signature, utf_sig)) + { + // Found it. + using namespace java::lang::reflect; + + // FIXME: Method must be public. Throw an exception? + if (! Modifier::isPublic (klass->methods[i].accflags)) + break; + + found_class = klass; + // Interface method indexes count from 1. + index = offset + 1; + return true; + } + + ++offset; + } + } + + // If we haven't found a match, and this class is an interface, then + // check all the superinterfaces. + if (search_class->isInterface()) + { + for (int i = 0; i < search_class->interface_count; ++i) + { + using namespace java::lang::reflect; + bool found = _Jv_getInterfaceMethod (search_class->interfaces[i], + found_class, index, + utf_name, utf_sig); + if (found) + return true; + } + } + + return false; +} + +#ifdef INTERPRETER +_Jv_MethodBase * +_Jv_FindInterpreterMethod (jclass klass, jmethodID desired_method) +{ + using namespace java::lang::reflect; + + _Jv_InterpClass *iclass + = reinterpret_cast<_Jv_InterpClass *> (klass->aux_info); + _Jv_MethodBase **imethods = _Jv_GetFirstMethod (iclass); + + for (int i = 0; i < JvNumMethods (klass); ++i) + { + _Jv_MethodBase *imeth = imethods[i]; + if (imeth->get_method () == desired_method) + return imeth; + } + + return NULL; +} +#endif + +// Return Utf8 name of a class. This function is here for code that +// can't access klass->name directly. +_Jv_Utf8Const* +_Jv_GetClassNameUtf8 (jclass klass) +{ + return klass->name; +} diff --git a/gcc-4.2.1/libjava/java/lang/natClassLoader.cc b/gcc-4.2.1/libjava/java/lang/natClassLoader.cc new file mode 100644 index 000000000..2400e0ce2 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natClassLoader.cc @@ -0,0 +1,624 @@ +// natClassLoader.cc - Implementation of java.lang.ClassLoader native methods. + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <execution.h> + +#include <java-threads.h> +#include <java-interp.h> + +#include <java/lang/Character.h> +#include <java/lang/Thread.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/InternalError.h> +#include <java/lang/IllegalAccessError.h> +#include <java/lang/LinkageError.h> +#include <java/lang/NoClassDefFoundError.h> +#include <java/lang/ClassNotFoundException.h> +#include <java/lang/ClassCircularityError.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/VMClassLoader.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/Runtime.h> +#include <java/lang/StringBuffer.h> +#include <java/io/Serializable.h> +#include <java/lang/Cloneable.h> +#include <java/util/HashMap.h> +#include <gnu/gcj/runtime/BootClassLoader.h> +#include <gnu/gcj/runtime/SystemClassLoader.h> + +// Size of local hash table. +#define HASH_LEN 1013 + +// Hash function for Utf8Consts. +#define HASH_UTF(Utf) ((Utf)->hash16() % HASH_LEN) + +// This records classes which will be registered with the system class +// loader when it is initialized. +static jclass system_class_list; + +// This is used as the value of system_class_list after we have +// initialized the system class loader; it lets us know that we should +// no longer pay attention to the system abi flag. +#define SYSTEM_LOADER_INITIALIZED ((jclass) -1) + +static jclass loaded_classes[HASH_LEN]; + +// This is the root of a linked list of classes +static jclass stack_head; + +// While bootstrapping we keep a list of classes we found, so that we +// can register their packages. There aren't many of these so we +// just keep a small buffer here and abort if we overflow. +#define BOOTSTRAP_CLASS_LIST_SIZE 20 +static jclass bootstrap_class_list[BOOTSTRAP_CLASS_LIST_SIZE]; +static int bootstrap_index; + + + + +jclass +java::lang::ClassLoader::loadClassFromSig(jstring name) +{ + int len = _Jv_GetStringUTFLength (name); + char sig[len + 1]; + _Jv_GetStringUTFRegion (name, 0, name->length(), sig); + jclass result = _Jv_FindClassFromSignature(sig, this); + if (result == NULL) + throw new ClassNotFoundException(name); + return result; +} + + + +// This tries to find a class in our built-in cache. This cache is +// used only for classes which are linked in to the executable or +// loaded via dlopen(). +jclass +_Jv_FindClassInCache (_Jv_Utf8Const *name) +{ + JvSynchronize sync (&java::lang::Class::class$); + jint hash = HASH_UTF (name); + + jclass klass; + for (klass = loaded_classes[hash]; klass; klass = klass->next_or_version) + { + if (_Jv_equalUtf8Consts (name, klass->name)) + break; + } + + return klass; +} + +void +_Jv_UnregisterClass (jclass the_class) +{ + // This can happen if the class could not be defined properly. + if (! the_class->name) + return; + + JvSynchronize sync (&java::lang::Class::class$); + jint hash = HASH_UTF(the_class->name); + + jclass *klass = &(loaded_classes[hash]); + for ( ; *klass; klass = &((*klass)->next_or_version)) + { + if (*klass == the_class) + { + *klass = (*klass)->next_or_version; + break; + } + } +} + +// Register an initiating class loader for a given class. +void +_Jv_RegisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) +{ + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + if (! loader) + { + // Very early in the bootstrap process, the Bootstrap classloader may + // not exist yet. + // FIXME: We could maintain a list of these and come back and register + // them later. + return; + } + loader->loadedClasses->put(klass->name->toString(), klass); +} + +// If we found an error while defining an interpreted class, we must +// go back and unregister it. +void +_Jv_UnregisterInitiatingLoader (jclass klass, java::lang::ClassLoader *loader) +{ + if (! loader) + loader = java::lang::VMClassLoader::bootLoader; + loader->loadedClasses->remove(klass->name->toString()); +} + + +// Class registration. +// +// There are two kinds of functions that register classes. +// +// Type 1: +// +// These take the address of a class that is in an object file. +// Because these classes are not allocated on the heap, It is also +// necessary to register the address of the object for garbage +// collection. This is used with the "old" C++ ABI and with +// -findirect-dispatch -fno-indirect-classes. +// +// Type 2: +// +// These take an initializer struct, create the class, and return the +// address of the newly created class to their caller. These are used +// with -findirect-dispatch. +// +// _Jv_RegisterClasses() and _Jv_RegisterClasses_Counted() are +// functions of Type 1, and _Jv_NewClassFromInitializer() and +// _Jv_RegisterNewClasses() are of Type 2. + + +// This function is called many times during startup, before main() is +// run. At that point in time we know for certain we are running +// single-threaded, so we don't need to lock when adding classes to the +// class chain. At all other times, the caller should synchronize on +// Class::class$. +void +_Jv_RegisterClasses (const jclass *classes) +{ + _Jv_RegisterLibForGc (classes); + + for (; *classes; ++classes) + { + jclass klass = *classes; + + if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version)) + (*_Jv_RegisterClassHook) (klass); + } +} + +// This is a version of _Jv_RegisterClasses that takes a count. +void +_Jv_RegisterClasses_Counted (const jclass * classes, size_t count) +{ + size_t i; + + _Jv_RegisterLibForGc (classes); + + for (i = 0; i < count; i++) + { + jclass klass = classes[i]; + + if (_Jv_CheckABIVersion ((unsigned long) klass->next_or_version)) + (*_Jv_RegisterClassHook) (klass); + } +} + +// Create a class on the heap from an initializer struct. +jclass +_Jv_NewClassFromInitializer (const char *class_initializer) +{ + /* We create an instance of java::lang::Class and copy all of its + fields except the first word (the vtable pointer) from + CLASS_INITIALIZER. This first word is pre-initialized by + _Jv_AllocObj, and we don't want to overwrite it. */ + + jclass new_class + = (jclass)_Jv_AllocObj (sizeof (java::lang::Class), + &java::lang::Class::class$); + const char *src = class_initializer + sizeof (void*); + char *dst = (char*)new_class + sizeof (void*); + size_t len = sizeof (*new_class) - sizeof (void*); + memcpy (dst, src, len); + + new_class->engine = &_Jv_soleIndirectCompiledEngine; + + /* FIXME: Way back before the dawn of time, we overloaded the + SYNTHETIC class access modifier to mean INTERPRETED. This was a + Bad Thing, but it didn't matter then because classes were never + marked synthetic. However, it is possible to redeem the + situation: _Jv_NewClassFromInitializer is only called from + compiled classes, so we clear the INTERPRETED flag. This is a + kludge! */ + new_class->accflags &= ~java::lang::reflect::Modifier::INTERPRETED; + + if (_Jv_CheckABIVersion ((unsigned long) new_class->next_or_version)) + (*_Jv_RegisterClassHook) (new_class); + + return new_class; +} + +// Called by compiler-generated code at DSO initialization. CLASSES +// is an array of pairs: the first item of each pair is a pointer to +// the initialized data that is a class initializer in a DSO, and the +// second is a pointer to a class reference. +// _Jv_NewClassFromInitializer() creates the new class (on the Java +// heap) and we write the address of the new class into the address +// pointed to by the second word. +void +_Jv_RegisterNewClasses (char **classes) +{ + _Jv_InitGC (); + + const char *initializer; + + while ((initializer = *classes++)) + { + jclass *class_ptr = (jclass *)*classes++; + *class_ptr = _Jv_NewClassFromInitializer (initializer); + } +} + +void +_Jv_RegisterClassHookDefault (jclass klass) +{ + // This is bogus, but there doesn't seem to be a better place to do + // it. + if (! klass->engine) + klass->engine = &_Jv_soleCompiledEngine; + + if (system_class_list != SYSTEM_LOADER_INITIALIZED) + { + unsigned long abi = (unsigned long) klass->next_or_version; + if (! _Jv_ClassForBootstrapLoader (abi)) + { + klass->next_or_version = system_class_list; + system_class_list = klass; + return; + } + } + + jint hash = HASH_UTF (klass->name); + + // If the class is already registered, don't re-register it. + for (jclass check_class = loaded_classes[hash]; + check_class != NULL; + check_class = check_class->next_or_version) + { + if (check_class == klass) + { + // If you get this, it means you have the same class in two + // different libraries. +#define TEXT "Duplicate class registration: " + // We size-limit MESSAGE so that you can't trash the stack. + char message[200]; + strcpy (message, TEXT); + strncpy (message + sizeof (TEXT) - 1, klass->name->chars(), + sizeof (message) - sizeof (TEXT)); + message[sizeof (message) - 1] = '\0'; + if (! gcj::runtimeInitialized) + JvFail (message); + else + { + java::lang::String *str = JvNewStringLatin1 (message); + throw new java::lang::VirtualMachineError (str); + } + } + } + + klass->next_or_version = loaded_classes[hash]; + loaded_classes[hash] = klass; +} + +// A pointer to a function that actually registers a class. +// Normally _Jv_RegisterClassHookDefault, but could be some other function +// that registers the class in e.g. a ClassLoader-local table. +// Should synchronize on Class:class$ while setting/restore this variable. + +void (*_Jv_RegisterClassHook) (jclass cl) = _Jv_RegisterClassHookDefault; + +void +_Jv_RegisterClass (jclass klass) +{ + jclass classes[2]; + classes[0] = klass; + classes[1] = NULL; + _Jv_RegisterClasses (classes); +} + +// This is used during initialization to register all compiled-in +// classes that are not part of the core with the system class loader. +void +_Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::SystemClassLoader *loader) +{ + for (jclass klass = system_class_list; + klass; + klass = klass->next_or_version) + { + klass->loader = loader; + loader->addClass(klass); + } + system_class_list = SYSTEM_LOADER_INITIALIZED; +} + +// An internal variant of _Jv_FindClass which simply swallows a +// NoClassDefFoundError or a ClassNotFoundException. This gives the +// caller a chance to evaluate the situation and behave accordingly. +jclass +_Jv_FindClassNoException (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +{ + jclass klass; + + try + { + klass = _Jv_FindClass(name, loader); + } + catch ( java::lang::NoClassDefFoundError *ncdfe ) + { + return NULL; + } + catch ( java::lang::ClassNotFoundException *cnfe ) + { + return NULL; + } + + return klass; +} + +jclass +_Jv_FindClass (_Jv_Utf8Const *name, java::lang::ClassLoader *loader) +{ + // See if the class was already loaded by this loader. This handles + // initiating loader checks, as we register classes with their + // initiating loaders. + + java::lang::ClassLoader *boot = java::lang::VMClassLoader::bootLoader; + java::lang::ClassLoader *real = loader; + if (! real) + real = boot; + jstring sname = name->toString(); + // We might still be bootstrapping the VM, in which case there + // won't be a bootstrap class loader yet. + jclass klass = real ? real->findLoadedClass (sname) : NULL; + + if (! klass) + { + if (loader) + { + // Load using a user-defined loader, jvmspec 5.3.2. + // Note that we explicitly must call the single-argument form. + klass = loader->loadClass(sname); + + // If "loader" delegated the loadClass operation to another + // loader, explicitly register that it is also an initiating + // loader of the given class. + java::lang::ClassLoader *delegate = (loader == boot + ? NULL + : loader); + if (klass && klass->getClassLoaderInternal () != delegate) + _Jv_RegisterInitiatingLoader (klass, loader); + } + else if (boot) + { + // Load using the bootstrap loader jvmspec 5.3.1. + klass = java::lang::VMClassLoader::loadClass (sname, false); + + // Register that we're an initiating loader. + if (klass) + _Jv_RegisterInitiatingLoader (klass, 0); + } + else + { + // Not even a bootstrap loader, try the built-in cache. + klass = _Jv_FindClassInCache (name); + + if (klass) + { + bool found = false; + for (int i = 0; i < bootstrap_index; ++i) + { + if (bootstrap_class_list[i] == klass) + { + found = true; + break; + } + } + if (! found) + { + if (bootstrap_index == BOOTSTRAP_CLASS_LIST_SIZE) + abort (); + bootstrap_class_list[bootstrap_index++] = klass; + } + } + } + } + + return klass; +} + +void +_Jv_RegisterBootstrapPackages () +{ + for (int i = 0; i < bootstrap_index; ++i) + java::lang::VMClassLoader::definePackageForNative(bootstrap_class_list[i]->getName()); +} + +jclass +_Jv_NewClass (_Jv_Utf8Const *name, jclass superclass, + java::lang::ClassLoader *loader) +{ + jclass ret = (jclass) _Jv_AllocObject (&java::lang::Class::class$); + ret->name = name; + ret->superclass = superclass; + ret->loader = loader; + + _Jv_RegisterInitiatingLoader (ret, loader); + + return ret; +} + +static _Jv_IDispatchTable *array_idt = NULL; +static jshort array_depth = 0; +static jclass *array_ancestors = NULL; + +static jclass interfaces[] = +{ + &java::lang::Cloneable::class$, + &java::io::Serializable::class$ +}; + +// Create a class representing an array of ELEMENT and store a pointer to it +// in element->arrayclass. LOADER is the ClassLoader which _initiated_ the +// instantiation of this array. ARRAY_VTABLE is the vtable to use for the new +// array class. This parameter is optional. +void +_Jv_NewArrayClass (jclass element, java::lang::ClassLoader *loader, + _Jv_VTable *array_vtable) +{ + JvSynchronize sync (element); + + _Jv_Utf8Const *array_name; + int len; + + if (element->arrayclass) + return; + + if (element->isPrimitive()) + { + if (element == JvPrimClass (void)) + throw new java::lang::ClassNotFoundException (); + len = 3; + } + else + len = element->name->len() + 5; + + { + char signature[len]; + int index = 0; + signature[index++] = '['; + // Compute name of array class. + if (element->isPrimitive()) + { + signature[index++] = (char) element->method_count; + } + else + { + size_t length = element->name->len(); + const char *const name = element->name->chars(); + if (name[0] != '[') + signature[index++] = 'L'; + memcpy (&signature[index], name, length); + index += length; + if (name[0] != '[') + signature[index++] = ';'; + } + array_name = _Jv_makeUtf8Const (signature, index); + } + + // Create new array class. + jclass array_class = _Jv_NewClass (array_name, &java::lang::Object::class$, + element->loader); + + // Note that `vtable_method_count' doesn't include the initial + // gc_descr slot. + int dm_count = java::lang::Object::class$.vtable_method_count; + + // Create a new vtable by copying Object's vtable. + _Jv_VTable *vtable; + if (array_vtable) + vtable = array_vtable; + else + vtable = _Jv_VTable::new_vtable (dm_count); + vtable->clas = array_class; + vtable->gc_descr = java::lang::Object::class$.vtable->gc_descr; + for (int i = 0; i < dm_count; ++i) + vtable->set_method (i, java::lang::Object::class$.vtable->get_method (i)); + + array_class->vtable = vtable; + array_class->vtable_method_count + = java::lang::Object::class$.vtable_method_count; + + // Stash the pointer to the element type. + array_class->element_type = element; + + // Register our interfaces. + array_class->interfaces = interfaces; + array_class->interface_count = sizeof interfaces / sizeof interfaces[0]; + + // Since all array classes have the same interface dispatch table, we can + // cache one and reuse it. It is not necessary to synchronize this. + if (!array_idt) + { + _Jv_Linker::wait_for_state(array_class, JV_STATE_PREPARED); + array_idt = array_class->idt; + array_depth = array_class->depth; + array_ancestors = array_class->ancestors; + } + else + { + array_class->idt = array_idt; + array_class->depth = array_depth; + array_class->ancestors = array_ancestors; + } + + using namespace java::lang::reflect; + { + // Array classes are "abstract final" and inherit accessibility + // from element type, per vmspec 5.3.3.2 + _Jv_ushort accflags = (Modifier::FINAL | Modifier::ABSTRACT + | (element->accflags + & (Modifier::PUBLIC | Modifier::PROTECTED + | Modifier::PRIVATE))); + array_class->accflags = accflags; + } + + // An array class has no visible instance fields. "length" is invisible to + // reflection. + + // Say this class is initialized and ready to go! + array_class->state = JV_STATE_DONE; + + // vmspec, section 5.3.3 describes this + if (element->loader != loader) + _Jv_RegisterInitiatingLoader (array_class, loader); + + element->arrayclass = array_class; +} + +// These two functions form a stack of classes. When a class is loaded +// it is pushed onto the stack by the class loader; this is so that +// StackTrace can quickly determine which classes have been loaded. + +jclass +_Jv_PopClass (void) +{ + JvSynchronize sync (&java::lang::Class::class$); + if (stack_head) + { + jclass tmp = stack_head; + stack_head = tmp->chain; + return tmp; + } + return NULL; +} + +void +_Jv_PushClass (jclass k) +{ + JvSynchronize sync (&java::lang::Class::class$); + jclass tmp = stack_head; + stack_head = k; + k->chain = tmp; +} diff --git a/gcc-4.2.1/libjava/java/lang/natDouble.cc b/gcc-4.2.1/libjava/java/lang/natDouble.cc new file mode 100644 index 000000000..1a33a5715 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natDouble.cc @@ -0,0 +1,214 @@ +// natDouble.cc - Implementation of java.lang.VMDouble native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <java/lang/String.h> +#include <java/lang/Double.h> +#include <java/lang/VMDouble.h> +#include <java/lang/Character.h> +#include <java/lang/NumberFormatException.h> +#include <jvm.h> + +#include <stdio.h> +#include <string.h> + +#include "fdlibm.h" + +union u +{ + jlong l; + jdouble d; +}; + +jlong +java::lang::VMDouble::doubleToLongBits(jdouble value) +{ + union u u; + u.d = value; + + jlong e = u.l & 0x7ff0000000000000LL; + jlong f = u.l & 0x000fffffffffffffLL; + + if (e == 0x7ff0000000000000LL && f != 0L) + u.l = 0x7ff8000000000000LL; + + return u.l; +} + +jlong +java::lang::VMDouble::doubleToRawLongBits(jdouble value) +{ + union u u; + u.d = value; + return u.l; +} + +jdouble +java::lang::VMDouble::longBitsToDouble(jlong bits) +{ + union u u; + u.l = bits; + return u.d; +} + +jstring +java::lang::VMDouble::toString(jdouble value, jboolean isFloat) +{ + if (Double::isNaN (value)) + return JvNewStringLatin1 ("NaN", sizeof ("NaN") - 1); + + if (value == Double::POSITIVE_INFINITY) + return JvNewStringLatin1 ("Infinity", sizeof ("Infinity") - 1); + + if (value == Double::NEGATIVE_INFINITY) + return JvNewStringLatin1 ("-Infinity", sizeof ("-Infinity") - 1); + + char buffer[50], result[50]; + int decpt, sign; + + _dtoa (value, 0, 20, &decpt, &sign, NULL, buffer, (int)isFloat); + + value = fabs (value); + + char *s = buffer; + char *d = result; + + if (sign) + *d++ = '-'; + + if (value >= 1e-3 && value < 1e7 || value == 0) + { + if (decpt <= 0) + *d++ = '0'; + else + { + for (int i = 0; i < decpt; i++) + if (*s) + *d++ = *s++; + else + *d++ = '0'; + } + + *d++ = '.'; + + if (*s == 0) + { + *d++ = '0'; + decpt++; + } + + while (decpt++ < 0) + *d++ = '0'; + + while (*s) + *d++ = *s++; + + *d = 0; + + return JvNewStringLatin1 (result, strlen (result)); + } + + *d++ = *s++; + decpt--; + *d++ = '.'; + + if (*s == 0) + *d++ = '0'; + + while (*s) + *d++ = *s++; + + *d++ = 'E'; + + if (decpt < 0) + { + *d++ = '-'; + decpt = -decpt; + } + + { + char exp[4]; + char *e = exp + sizeof exp; + + *--e = 0; + do + { + *--e = '0' + decpt % 10; + decpt /= 10; + } + while (decpt > 0); + + while (*e) + *d++ = *e++; + } + + *d = 0; + + return JvNewStringLatin1 (result, strlen (result)); +} + +jdouble +java::lang::VMDouble::parseDouble(jstring str) +{ + int length = str->length(); + + while (length > 0 + && Character::isWhitespace(str->charAt(length - 1))) + length--; + + // The String could end with a f/F/d/D which is valid but we don't need. + bool saw_trailer = false; + if (length > 0) + { + jchar last = str->charAt(length-1); + if (last == 'f' || last == 'F' || last == 'd' || last == 'D') + { + length--; + saw_trailer = true; + } + } + + jsize start = 0; + while (length > 0 + && Character::isWhitespace(str->charAt(start))) + start++, length--; + + if (length > 0) + { + // Note that UTF can expand 3x. + char *data = (char *) __builtin_alloca (3 * length + 1); + jsize blength = _Jv_GetStringUTFRegion (str, start, length, data); + data[blength] = 0; + + if (! saw_trailer) + { + if (! strcmp (data, "NaN") || ! strcmp (data, "+NaN") + || ! strcmp (data, "-NaN")) + return Double::NaN; + else if (! strcmp (data, "Infinity") || ! strcmp (data, "+Infinity")) + return Double::POSITIVE_INFINITY; + else if (! strcmp (data, "-Infinity")) + return Double::NEGATIVE_INFINITY; + } + + struct _Jv_reent reent; + memset (&reent, 0, sizeof reent); + + char *endptr; + double val = _strtod_r (&reent, data, &endptr); + if (endptr == data + blength) + return val; + } + throw new NumberFormatException(str); +} diff --git a/gcc-4.2.1/libjava/java/lang/natEcosProcess.cc b/gcc-4.2.1/libjava/java/lang/natEcosProcess.cc new file mode 100644 index 000000000..9cfb19e70 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natEcosProcess.cc @@ -0,0 +1,25 @@ +// natEcosProcess.cc - Native side of eCos processes. + +/* Copyright (C) 1998, 1999 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// The configury system needs this file to exist, since we can't +// really conditionally link files (an autoconf bug). To avoid having +// an empty translation unit, we make a single method native. FIXME. + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/lang/ConcreteProcess.h> + +void +java::lang::ConcreteProcess::destroy (void) +{ +} diff --git a/gcc-4.2.1/libjava/java/lang/natFloat.cc b/gcc-4.2.1/libjava/java/lang/natFloat.cc new file mode 100644 index 000000000..f090b815e --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natFloat.cc @@ -0,0 +1,52 @@ +// natFloat.cc - Implementation of java.lang.VMFloat native methods. + +/* Copyright (C) 1998, 1999, 2001, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <java/lang/Float.h> +#include <java/lang/VMFloat.h> +#include <jvm.h> + +union u +{ + jint l; + jfloat d; +}; + +jint +java::lang::VMFloat::floatToIntBits(jfloat value) +{ + union u u; + u.d = value; + jint e = u.l & 0x7f800000; + jint f = u.l & 0x007fffff; + + if (e == 0x7f800000 && f != 0) + u.l = 0x7fc00000; + + return u.l; +} + +jint +java::lang::VMFloat::floatToRawIntBits(jfloat value) +{ + union u u; + u.d = value; + return u.l; +} + +jfloat +java::lang::VMFloat::intBitsToFloat(jint bits) +{ + union u u; + u.l = bits; + return u.d; +} + diff --git a/gcc-4.2.1/libjava/java/lang/natMath.cc b/gcc-4.2.1/libjava/java/lang/natMath.cc new file mode 100644 index 000000000..d86d6307d --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natMath.cc @@ -0,0 +1,184 @@ +/* Copyright (C) 1998, 1999, 2000, 2002, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/** + * @author Andrew Haley <aph@cygnus.com> + * @date Tue Sep 22 1998 */ +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3 + * "The Java Language Specification", ISBN 0-201-63451-1 + * plus online API docs for JDK 1.2 beta from http://www.javasoft.com. + * Status: Believed complete and correct. + */ + +#include <config.h> + +#include <java/lang/String.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Math.h> +#include <gcj/array.h> + +#include "fdlibm.h" + +jdouble java::lang::Math::cos(jdouble x) +{ + return (jdouble)::cos((double)x); +} + +jdouble java::lang::Math::sin(jdouble x) +{ + return (jdouble)::sin((double)x); +} + +jdouble java::lang::Math::tan(jdouble x) +{ + return (jdouble)::tan((double)x); +} + +jdouble java::lang::Math::asin(jdouble x) +{ + return (jdouble)::asin((double)x); +} + +jdouble java::lang::Math::acos(jdouble x) +{ + return (jdouble)::acos((double)x); +} + +jdouble java::lang::Math::atan(jdouble x) +{ + return (jdouble)::atan((double)x); +} + +jdouble java::lang::Math::atan2(jdouble y, jdouble x) +{ + return (jdouble)::atan2((double)y, (double)x); +} + +jdouble java::lang::Math::log(jdouble x) +{ + return (jdouble)::log((double)x); +} + +jdouble java::lang::Math::exp(jdouble x) +{ + return (jdouble)::exp((double)x); +} + +jdouble java::lang::Math::sqrt(jdouble x) +{ + return (jdouble)::sqrt((double)x); +} + +jdouble java::lang::Math::pow(jdouble y, jdouble x) +{ + return (jdouble)::pow((double)y, (double)x); +} + +jdouble java::lang::Math::IEEEremainder(jdouble y, jdouble x) +{ + return (jdouble)::__ieee754_remainder((double)y, (double)x); +} + +jdouble java::lang::Math::rint(jdouble x) +{ + return (jdouble)::rint((double)x); +} + +jdouble java::lang::Math::floor(jdouble x) +{ + return (jdouble)::floor((double)x); +} + +jdouble java::lang::Math::ceil(jdouble x) +{ + return (jdouble)::ceil((double)x); +} + +jdouble java::lang::Math::log10(jdouble x) +{ + return (jdouble)::log10((double)x); +} + +jdouble java::lang::Math::cbrt(jdouble x) +{ + return (jdouble)::cbrt((double)x); +} + +jdouble java::lang::Math::cosh(jdouble x) +{ + return (jdouble)::cosh((double)x); +} + +jdouble java::lang::Math::expm1(jdouble x) +{ + return (jdouble)::expm1((double)x); +} + +jdouble java::lang::Math::hypot(jdouble x, jdouble y) +{ + return (jdouble)::hypot((double)x, (double)y); +} + +jdouble java::lang::Math::log1p(jdouble x) +{ + return (jdouble)::log1p((double)x); +} + +jdouble java::lang::Math::sinh(jdouble x) +{ + return (jdouble)::sinh((double)x); +} + +jdouble java::lang::Math::tanh(jdouble x) +{ + return (jdouble)::tanh((double)x); +} + +static inline int +floatToIntBits (jfloat value) +{ + union { + jint l; + jfloat d; + } u; + u.d = value; + return u.l; +} + +static inline bool +isNaN (jint bits) +{ + jint e = bits & 0x7f800000; + jint f = bits & 0x007fffff; + + return e == 0x7f800000 && f != 0; +} + +static inline jlong +doubleToLongBits (jdouble value) +{ + union { + jlong l; + jdouble d; + } u; + u.d = value; + return u.l; +} + +static inline bool +isNaN (jlong bits) +{ + jlong e = bits & 0x7ff0000000000000LL; + jlong f = bits & 0x000fffffffffffffLL; + + return e == 0x7ff0000000000000LL && f != 0LL; +} + diff --git a/gcc-4.2.1/libjava/java/lang/natObject.cc b/gcc-4.2.1/libjava/java/lang/natObject.cc new file mode 100644 index 000000000..87f2044dd --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natObject.cc @@ -0,0 +1,1457 @@ +// natObject.cc - Implementation of the Object class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <string.h> + +#pragma implementation "Object.h" + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/Object.h> +#include <java-threads.h> +#include <java-signal.h> +#include <java/lang/CloneNotSupportedException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalMonitorStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Class.h> +#include <java/lang/Cloneable.h> +#include <java/lang/Thread.h> + +#ifdef LOCK_DEBUG +# include <stdio.h> +#endif + + + +using namespace java::lang; + +// This is used to represent synchronization information. +struct _Jv_SyncInfo +{ +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // We only need to keep track of initialization state if we can + // possibly finalize this object. + bool init; +#endif + _Jv_ConditionVariable_t condition; + _Jv_Mutex_t mutex; +}; + + + +jclass +java::lang::Object::getClass (void) +{ + _Jv_VTable **dt = (_Jv_VTable **) this; + return (*dt)->clas; +} + +jint +java::lang::Object::hashCode (void) +{ + return _Jv_HashCode (this); +} + +jobject +java::lang::Object::clone (void) +{ + jclass klass = getClass (); + jobject r; + jint size; + + // We also clone arrays here. If we put the array code into + // __JArray, then we'd have to figure out a way to find the array + // vtbl when creating a new array class. This is easier, if uglier. + if (klass->isArray()) + { + __JArray *array = (__JArray *) this; + jclass comp = getClass()->getComponentType(); + jint eltsize; + if (comp->isPrimitive()) + { + r = _Jv_NewPrimArray (comp, array->length); + eltsize = comp->size(); + } + else + { + r = _Jv_NewObjectArray (array->length, comp, NULL); + eltsize = sizeof (jobject); + } + // We can't use sizeof on __JArray because we must account for + // alignment of the element type. + size = (_Jv_GetArrayElementFromElementType (array, comp) - (char *) array + + array->length * eltsize); + } + else + { + if (! java::lang::Cloneable::class$.isAssignableFrom(klass)) + throw new CloneNotSupportedException; + + size = klass->size(); + r = _Jv_AllocObject (klass); + } + + memcpy ((void *) r, (void *) this, size); +#ifndef JV_HASH_SYNCHRONIZATION + // Guarantee that the locks associated to the two objects are + // distinct. + r->sync_info = NULL; +#endif + return r; +} + +void +_Jv_FinalizeObject (jobject obj) +{ + // Ignore exceptions. From section 12.6 of the Java Language Spec. + try + { + obj->finalize (); + } + catch (java::lang::Throwable *t) + { + // Ignore. + } +} + + +// +// Synchronization code. +// + +#ifndef JV_HASH_SYNCHRONIZATION +// This global is used to make sure that only one thread sets an +// object's `sync_info' field. +static _Jv_Mutex_t sync_mutex; + +// This macro is used to see if synchronization initialization is +// needed. +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) +# define INIT_NEEDED(Obj) (! (Obj)->sync_info \ + || ! ((_Jv_SyncInfo *) ((Obj)->sync_info))->init) +#else +# define INIT_NEEDED(Obj) (! (Obj)->sync_info) +#endif + +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) +// If we have to run a destructor for a sync_info member, then this +// function is registered as a finalizer for the sync_info. +static void +finalize_sync_info (jobject obj) +{ + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj; +#if defined (_Jv_HaveCondDestroy) + _Jv_CondDestroy (&si->condition); +#endif +#if defined (_Jv_HaveMutexDestroy) + _Jv_MutexDestroy (&si->mutex); +#endif + si->init = false; +} +#endif + +// This is called to initialize the sync_info element of an object. +void +java::lang::Object::sync_init (void) +{ + _Jv_MutexLock (&sync_mutex); + // Check again to see if initialization is needed now that we have + // the lock. + if (INIT_NEEDED (this)) + { + // We assume there are no pointers in the sync_info + // representation. + _Jv_SyncInfo *si; + // We always create a new sync_info, even if there is already + // one available. Any given object can only be finalized once. + // If we get here and sync_info is not null, then it has already + // been finalized. So if we just reinitialize the old one, + // we'll never be able to (re-)destroy the mutex and/or + // condition variable. + si = (_Jv_SyncInfo *) _Jv_AllocBytes (sizeof (_Jv_SyncInfo)); + _Jv_MutexInit (&si->mutex); + _Jv_CondInit (&si->condition); +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // Register a finalizer. + si->init = true; + _Jv_RegisterFinalizer (si, finalize_sync_info); +#endif + sync_info = (jobject) si; + } + _Jv_MutexUnlock (&sync_mutex); +} + +void +java::lang::Object::notify (void) +{ + if (__builtin_expect (INIT_NEEDED (this), false)) + sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; + if (__builtin_expect (_Jv_CondNotify (&si->condition, &si->mutex), false)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +void +java::lang::Object::notifyAll (void) +{ + if (__builtin_expect (INIT_NEEDED (this), false)) + sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; + if (__builtin_expect (_Jv_CondNotifyAll (&si->condition, &si->mutex), false)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +void +java::lang::Object::wait (jlong timeout, jint nanos) +{ + if (__builtin_expect (INIT_NEEDED (this), false)) + sync_init (); + if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, false)) + throw new IllegalArgumentException; + _Jv_SyncInfo *si = (_Jv_SyncInfo *) sync_info; + switch (_Jv_CondWait (&si->condition, &si->mutex, timeout, nanos)) + { + case _JV_NOT_OWNER: + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + case _JV_INTERRUPTED: + if (Thread::interrupted ()) + throw new InterruptedException; + } +} + +// +// Some runtime code. +// + +// This function is called at system startup to initialize the +// `sync_mutex'. +void +_Jv_InitializeSyncMutex (void) +{ + _Jv_MutexInit (&sync_mutex); +} + +void +_Jv_MonitorEnter (jobject obj) +{ +#ifndef HANDLE_SEGV + if (__builtin_expect (! obj, false)) + throw new java::lang::NullPointerException; +#endif + if (__builtin_expect (INIT_NEEDED (obj), false)) + obj->sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; + _Jv_MutexLock (&si->mutex); + // FIXME: In the Windows case, this can return a nonzero error code. + // We should turn that into some exception ... +} + +void +_Jv_MonitorExit (jobject obj) +{ + JvAssert (obj); + JvAssert (! INIT_NEEDED (obj)); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; + if (__builtin_expect (_Jv_MutexUnlock (&si->mutex), false)) + throw new java::lang::IllegalMonitorStateException; +} + +bool +_Jv_ObjectCheckMonitor (jobject obj) +{ + if (__builtin_expect (INIT_NEEDED (obj), false)) + obj->sync_init (); + _Jv_SyncInfo *si = (_Jv_SyncInfo *) obj->sync_info; + return _Jv_MutexCheckMonitor (&si->mutex); +} + +#else /* JV_HASH_SYNCHRONIZATION */ + +// FIXME: We shouldn't be calling GC_register_finalizer directly. +#ifndef HAVE_BOEHM_GC +# error Hash synchronization currently requires boehm-gc +// That's actually a bit of a lie: It should also work with the null GC, +// probably even better than the alternative. +// To really support alternate GCs here, we would need to widen the +// interface to finalization, since we sometimes have to register a +// second finalizer for an object that already has one. +// We might also want to move the GC interface to a .h file, since +// the number of procedure call levels involved in some of these +// operations is already ridiculous, and would become worse if we +// went through the proper intermediaries. +#else +# ifdef LIBGCJ_GC_DEBUG +# define GC_DEBUG +# endif +# include "gc.h" +#endif + +// What follows currenly assumes a Linux-like platform. +// Some of it specifically assumes X86 or IA64 Linux, though that +// should be easily fixable. + +// A Java monitor implemention based on a table of locks. +// Each entry in the table describes +// locks held for objects that hash to that location. +// This started out as a reimplementation of the technique used in SGIs JVM, +// for which we obtained permission from SGI. +// But in fact, this ended up quite different, though some ideas are +// still shared with the original. +// It was also influenced by some of the published IBM work, +// though it also differs in many ways from that. +// We could speed this up if we had a way to atomically update +// an entire cache entry, i.e. 2 contiguous words of memory. +// That would usually be the case with a 32 bit ABI on a 64 bit processor. +// But we don't currently go out of our way to target those. +// I don't know how to do much better with a N bit ABI on a processor +// that can atomically update only N bits at a time. +// Author: Hans-J. Boehm (Hans_Boehm@hp.com, boehm@acm.org) + +#include <limits.h> +#include <unistd.h> // for usleep, sysconf. +#include <gcj/javaprims.h> +#include <sysdep/locks.h> +#include <java/lang/Thread.h> + +// Try to determine whether we are on a multiprocessor, i.e. whether +// spinning may be profitable. +// This should really use a suitable autoconf macro. +// False is the conservative answer, though the right one is much better. +static bool +is_mp() +{ +#ifdef _SC_NPROCESSORS_ONLN + long nprocs = sysconf(_SC_NPROCESSORS_ONLN); + return (nprocs > 1); +#else + return false; +#endif +} + +// A call to keep_live(p) forces p to be accessible to the GC +// at this point. +inline static void +keep_live(obj_addr_t p) +{ + __asm__ __volatile__("" : : "rm"(p) : "memory"); +} + +// Each hash table entry holds a single preallocated "lightweight" lock. +// In addition, it holds a chain of "heavyweight" locks. Lightweight +// locks do not support Object.wait(), and are converted to heavyweight +// status in response to contention. Unlike the SGI scheme, both +// ligtweight and heavyweight locks in one hash entry can be simultaneously +// in use. (The SGI scheme requires that we be able to acquire a heavyweight +// lock on behalf of another thread, and can thus convert a lock we don't +// hold to heavyweight status. Here we don't insist on that, and thus +// let the original holder of the lighweight lock keep it.) + +struct heavy_lock { + void * reserved_for_gc; + struct heavy_lock *next; // Hash chain link. + // Traced by GC. + void * old_client_data; // The only other field traced by GC. + GC_finalization_proc old_finalization_proc; + obj_addr_t address; // Object to which this lock corresponds. + // Should not be traced by GC. + // Cleared as heavy_lock is destroyed. + // Together with the rest of the heavy lock + // chain, this is protected by the lock + // bit in the hash table entry to which + // the chain is attached. + _Jv_SyncInfo si; + // The remaining fields save prior finalization info for + // the object, which we needed to replace in order to arrange + // for cleanup of the lock structure. +}; + +#ifdef LOCK_DEBUG +void +print_hl_list(heavy_lock *hl) +{ + heavy_lock *p = hl; + for (; 0 != p; p = p->next) + fprintf (stderr, "(hl = %p, addr = %p)", p, (void *)(p -> address)); +} +#endif /* LOCK_DEBUG */ + +#if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) +// If we have to run a destructor for a sync_info member, then this +// function could be registered as a finalizer for the sync_info. +// In fact, we now only invoke it explicitly. +static inline void +heavy_lock_finalization_proc (heavy_lock *hl) +{ +#if defined (_Jv_HaveCondDestroy) + _Jv_CondDestroy (&hl->si.condition); +#endif +#if defined (_Jv_HaveMutexDestroy) + _Jv_MutexDestroy (&hl->si.mutex); +#endif + hl->si.init = false; +} +#endif /* defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) */ + +// We convert the lock back to lightweight status when +// we exit, so that a single contention episode doesn't doom the lock +// forever. But we also need to make sure that lock structures for dead +// objects are eventually reclaimed. We do that in a an additional +// finalizer on the underlying object. +// Note that if the corresponding object is dead, it is safe to drop +// the heavy_lock structure from its list. It is not necessarily +// safe to deallocate it, since the unlock code could still be running. + +struct hash_entry { + volatile obj_addr_t address; // Address of object for which lightweight + // k is held. + // We assume the 3 low order bits are zero. + // With the Boehm collector and bitmap + // allocation, objects of size 4 bytes are + // broken anyway. Thus this is primarily + // a constraint on statically allocated + // objects used for synchronization. + // This allows us to use the low order + // bits as follows: +# define LOCKED 1 // This hash entry is locked, and its + // state may be invalid. + // The lock protects both the hash_entry + // itself (except for the light_count + // and light_thr_id fields, which + // are protected by the lightweight + // lock itself), and any heavy_monitor + // structures attached to it. +# define HEAVY 2 // Heavyweight locks associated with this + // hash entry may be held. + // The lightweight entry is still valid, + // if the leading bits of the address + // field are nonzero. + // If the LOCKED bit is clear, then this is + // set exactly when heavy_count is > 0 . + // Stored redundantly so a single + // compare-and-swap works in the easy case. + // If HEAVY is not set, it is safe to use + // an available lightweight lock entry + // without checking if there is an existing + // heavyweight lock for the same object. + // (There may be one, but it won't be held + // or waited for.) +# define REQUEST_CONVERSION 4 // The lightweight lock is held. But + // one or more other threads have tried + // to acquire the lock, and hence request + // conversion to heavyweight status. + // The heavyweight lock is already allocated. + // Threads requesting conversion are + // waiting on the condition variable associated + // with the heavyweight lock. + // Not used for conversion due to + // Object.wait() calls. +# define FLAGS (LOCKED | HEAVY | REQUEST_CONVERSION) + volatile _Jv_ThreadId_t light_thr_id; + // Thr_id of holder of lightweight lock. + // Only updated by lightweight lock holder. + // Must be recognizably invalid if the + // lightweight lock is not held. +# define INVALID_THREAD_ID 0 // Works for Linux? + // If zero doesn't work, we have to + // initialize lock table. + volatile unsigned short light_count; + // Number of times the lightweight lock + // is held minus one. Zero if lightweight + // lock is not held. Only updated by + // lightweight lock holder or, in one + // case, while holding the LOCKED bit in + // a state in which there can be no + // lightweight lock holder. + unsigned short heavy_count; // Total number of times heavyweight locks + // associated with this hash entry are held + // or waiting to be acquired. + // Threads in wait() are included eventhough + // they have temporarily released the lock. + // Protected by LOCKED bit. + // Threads requesting conversion to heavyweight + // status are also included. + struct heavy_lock * heavy_locks; + // Chain of heavy locks. Protected + // by lockbit for he. Locks may + // remain allocated here even if HEAVY + // is not set and heavy_count is 0. + // If a lightweight and heavyweight lock + // correspond to the same address, the + // lightweight lock is the right one. +}; + +#ifndef JV_SYNC_TABLE_SZ +# define JV_SYNC_TABLE_SZ 2048 // Must be power of 2. +#endif + +hash_entry light_locks[JV_SYNC_TABLE_SZ]; + +#define JV_SYNC_HASH(p) (((long)p ^ ((long)p >> 10)) & (JV_SYNC_TABLE_SZ-1)) + +// Note that the light_locks table is scanned conservatively by the +// collector. It is essential the the heavy_locks field is scanned. +// Currently the address field may or may not cause the associated object +// to be retained, depending on whether flag bits are set. +// This means that we can conceivable get an unexpected deadlock if +// 1) Object at address A is locked. +// 2) The client drops A without unlocking it. +// 3) Flag bits in the address entry are set, so the collector reclaims +// the object at A. +// 4) A is reallocated, and an attempt is made to lock the result. +// This could be fixed by scanning light_locks in a more customized +// manner that ignores the flag bits. But it can only happen with hand +// generated semi-illegal .class files, and then it doesn't present a +// security hole. + +#ifdef LOCK_DEBUG + void print_he(hash_entry *he) + { + fprintf(stderr, "lock hash entry = %p, index = %d, address = 0x%lx\n" + "\tlight_thr_id = 0x%lx, light_count = %d, " + "heavy_count = %d\n\theavy_locks:", he, + he - light_locks, (unsigned long)(he -> address), + (unsigned long)(he -> light_thr_id), + he -> light_count, he -> heavy_count); + print_hl_list(he -> heavy_locks); + fprintf(stderr, "\n"); + } +#endif /* LOCK_DEBUG */ + +#ifdef LOCK_LOG + // Log locking operations. For debugging only. + // Logging is intended to be as unintrusive as possible. + // Log calls are made after an operation completes, and hence + // may not completely reflect actual synchronization ordering. + // The choice of events to log is currently a bit haphazard. + // The intent is that if we have to track down any other bugs + // inthis code, we extend the logging as appropriate. + typedef enum + { + ACQ_LIGHT, ACQ_LIGHT2, ACQ_HEAVY, ACQ_HEAVY2, PROMOTE, REL_LIGHT, + REL_HEAVY, REQ_CONV, PROMOTE2, WAIT_START, WAIT_END, NOTIFY, NOTIFY_ALL + } event_type; + + struct lock_history + { + event_type tp; + obj_addr_t addr; // Often includes flags. + _Jv_ThreadId_t thr; + }; + + const int LOG_SIZE = 128; // Power of 2. + + lock_history lock_log[LOG_SIZE]; + + volatile obj_addr_t log_next = 0; + // Next location in lock_log. + // Really an int, but we need compare_and_swap. + + static void add_log_entry(event_type t, obj_addr_t a, _Jv_ThreadId_t th) + { + obj_addr_t my_entry; + obj_addr_t next_entry; + do + { + my_entry = log_next; + next_entry = ((my_entry + 1) & (LOG_SIZE - 1)); + } + while (!compare_and_swap(&log_next, my_entry, next_entry)); + lock_log[my_entry].tp = t; + lock_log[my_entry].addr = a; + lock_log[my_entry].thr = th; + } + +# define LOG(t, a, th) add_log_entry(t, a, th) +#else /* !LOCK_LOG */ +# define LOG(t, a, th) +#endif + +static bool mp = false; // Known multiprocesssor. + +// Wait for roughly 2^n units, touching as little memory as possible. +static void +spin(unsigned n) +{ + const unsigned MP_SPINS = 10; + const unsigned YIELDS = 4; + const unsigned SPINS_PER_UNIT = 30; + const unsigned MIN_SLEEP_USECS = 2001; // Shorter times spin under Linux. + const unsigned MAX_SLEEP_USECS = 200000; + static unsigned spin_limit = 0; + static unsigned yield_limit = YIELDS; + static bool spin_initialized = false; + + if (!spin_initialized) + { + mp = is_mp(); + if (mp) + { + spin_limit = MP_SPINS; + yield_limit = MP_SPINS + YIELDS; + } + spin_initialized = true; + } + if (n < spin_limit) + { + unsigned i = SPINS_PER_UNIT << n; + for (; i > 0; --i) + __asm__ __volatile__(""); + } + else if (n < yield_limit) + { + _Jv_ThreadYield(); + } + else + { + unsigned duration = MIN_SLEEP_USECS << (n - yield_limit); + if (n >= 15 + yield_limit || duration > MAX_SLEEP_USECS) + duration = MAX_SLEEP_USECS; + _Jv_platform_usleep(duration); + } +} + +// Wait for a hash entry to become unlocked. +static void +wait_unlocked (hash_entry *he) +{ + unsigned i = 0; + while (he -> address & LOCKED) + spin (i++); +} + +// Return the heavy lock for addr if it was already allocated. +// The client passes in the appropriate hash_entry. +// We hold the lock for he. +static inline heavy_lock * +find_heavy (obj_addr_t addr, hash_entry *he) +{ + heavy_lock *hl = he -> heavy_locks; + while (hl != 0 && hl -> address != addr) hl = hl -> next; + return hl; +} + +// Unlink the heavy lock for the given address from its hash table chain. +// Dies miserably and conspicuously if it's not there, since that should +// be impossible. +static inline void +unlink_heavy (obj_addr_t addr, hash_entry *he) +{ + heavy_lock **currentp = &(he -> heavy_locks); + while ((*currentp) -> address != addr) + currentp = &((*currentp) -> next); + *currentp = (*currentp) -> next; +} + +// Finalization procedure for objects that have associated heavy-weight +// locks. This may replace the real finalization procedure. +static void +heavy_lock_obj_finalization_proc (void *obj, void *cd) +{ + heavy_lock *hl = (heavy_lock *)cd; + +// This only addresses misalignment of statics, not heap objects. It +// works only because registering statics for finalization is a noop, +// no matter what the least significant bits are. +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)0x7); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + hash_entry *he = light_locks + JV_SYNC_HASH(addr); + obj_addr_t he_address = (he -> address & ~LOCKED); + + // Acquire lock bit immediately. It's possible that the hl was already + // destroyed while we were waiting for the finalizer to run. If it + // was, the address field was set to zero. The address filed access is + // protected by the lock bit to ensure that we do this exactly once. + // The lock bit also protects updates to the objects finalizer. + while (!compare_and_swap(&(he -> address), he_address, he_address|LOCKED )) + { + // Hash table entry is currently locked. We can't safely + // touch the list of heavy locks. + wait_unlocked(he); + he_address = (he -> address & ~LOCKED); + } + if (0 == hl -> address) + { + // remove_all_heavy destroyed hl, and took care of the real finalizer. + release_set(&(he -> address), he_address); + return; + } + JvAssert(hl -> address == addr); + GC_finalization_proc old_finalization_proc = hl -> old_finalization_proc; + if (old_finalization_proc != 0) + { + // We still need to run a real finalizer. In an idealized + // world, in which people write thread-safe finalizers, that is + // likely to require synchronization. Thus we reregister + // ourselves as the only finalizer, and simply run the real one. + // Thus we don't clean up the lock yet, but we're likely to do so + // on the next GC cycle. + // It's OK if remove_all_heavy actually destroys the heavy lock, + // since we've updated old_finalization_proc, and thus the user's + // finalizer won't be rerun. + void * old_client_data = hl -> old_client_data; + hl -> old_finalization_proc = 0; + hl -> old_client_data = 0; +# ifdef HAVE_BOEHM_GC + GC_REGISTER_FINALIZER_NO_ORDER(obj, heavy_lock_obj_finalization_proc, cd, 0, 0); +# endif + release_set(&(he -> address), he_address); + old_finalization_proc(obj, old_client_data); + } + else + { + // The object is really dead, although it's conceivable that + // some thread may still be in the process of releasing the + // heavy lock. Unlink it and, if necessary, register a finalizer + // to destroy sync_info. + unlink_heavy(addr, he); + hl -> address = 0; // Don't destroy it again. + release_set(&(he -> address), he_address); +# if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // Make sure lock is not held and then destroy condvar and mutex. + _Jv_MutexLock(&(hl->si.mutex)); + _Jv_MutexUnlock(&(hl->si.mutex)); + heavy_lock_finalization_proc (hl); +# endif + } +} + +// We hold the lock on he, and heavy_count is 0. +// Release the lock by replacing the address with new_address_val. +// Remove all heavy locks on the list. Note that the only possible way +// in which a lock may still be in use is if it's in the process of +// being unlocked. +// FIXME: Why does this unlock the hash entry? I think that +// could now be done more cleanly in MonitorExit. +static void +remove_all_heavy (hash_entry *he, obj_addr_t new_address_val) +{ + JvAssert(he -> heavy_count == 0); + JvAssert(he -> address & LOCKED); + heavy_lock *hl = he -> heavy_locks; + he -> heavy_locks = 0; + // We would really like to release the lock bit here. Unfortunately, that + // Creates a race between or finalizer removal, and the potential + // reinstallation of a new finalizer as a new heavy lock is created. + // This may need to be revisited. + for(; 0 != hl; hl = hl->next) + { + obj_addr_t obj = hl -> address; + JvAssert(0 != obj); // If this was previously finalized, it should no + // longer appear on our list. + hl -> address = 0; // Finalization proc might still see it after we + // finish. + GC_finalization_proc old_finalization_proc = hl -> old_finalization_proc; + void * old_client_data = hl -> old_client_data; +# ifdef HAVE_BOEHM_GC + // Remove our finalization procedure. + // Reregister the clients if applicable. + GC_REGISTER_FINALIZER_NO_ORDER((GC_PTR)obj, old_finalization_proc, + old_client_data, 0, 0); + // Note that our old finalization procedure may have been + // previously determined to be runnable, and may still run. + // FIXME - direct dependency on boehm GC. +# endif +# if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + // Wait for a possible lock holder to finish unlocking it. + // This is only an issue if we have to explicitly destroy the mutex + // or possibly if we have to destroy a condition variable that is + // still being notified. + _Jv_MutexLock(&(hl->si.mutex)); + _Jv_MutexUnlock(&(hl->si.mutex)); + heavy_lock_finalization_proc (hl); +# endif + } + release_set(&(he -> address), new_address_val); +} + +// We hold the lock on he and heavy_count is 0. +// We release it by replacing the address field with new_address_val. +// Remove all heavy locks on the list if the list is sufficiently long. +// This is called periodically to avoid very long lists of heavy locks. +// This seems to otherwise become an issue with SPECjbb, for example. +static inline void +maybe_remove_all_heavy (hash_entry *he, obj_addr_t new_address_val) +{ + static const int max_len = 5; + heavy_lock *hl = he -> heavy_locks; + + for (int i = 0; i < max_len; ++i) + { + if (0 == hl) + { + release_set(&(he -> address), new_address_val); + return; + } + hl = hl -> next; + } + remove_all_heavy(he, new_address_val); +} + +// Allocate a new heavy lock for addr, returning its address. +// Assumes we already have the hash_entry locked, and there +// is currently no lightweight or allocated lock for addr. +// We register a finalizer for addr, which is responsible for +// removing the heavy lock when addr goes away, in addition +// to the responsibilities of any prior finalizer. +// This unfortunately holds the lock bit for the hash entry while it +// allocates two objects (on for the finalizer). +// It would be nice to avoid that somehow ... +static heavy_lock * +alloc_heavy(obj_addr_t addr, hash_entry *he) +{ + heavy_lock * hl = (heavy_lock *) _Jv_AllocTraceTwo(sizeof (heavy_lock)); + + hl -> address = addr; + _Jv_MutexInit (&(hl -> si.mutex)); + _Jv_CondInit (&(hl -> si.condition)); +# if defined (_Jv_HaveCondDestroy) || defined (_Jv_HaveMutexDestroy) + hl->si.init = true; // needed ? +# endif + hl -> next = he -> heavy_locks; + he -> heavy_locks = hl; + // FIXME: The only call that cheats and goes directly to the GC interface. +# ifdef HAVE_BOEHM_GC + GC_REGISTER_FINALIZER_NO_ORDER( + (void *)addr, heavy_lock_obj_finalization_proc, + hl, &hl->old_finalization_proc, + &hl->old_client_data); +# endif /* HAVE_BOEHM_GC */ + return hl; +} + +// Return the heavy lock for addr, allocating if necessary. +// Assumes we have the cache entry locked, and there is no lightweight +// lock for addr. +static heavy_lock * +get_heavy(obj_addr_t addr, hash_entry *he) +{ + heavy_lock *hl = find_heavy(addr, he); + if (0 == hl) + hl = alloc_heavy(addr, he); + return hl; +} + +void +_Jv_MonitorEnter (jobject obj) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + obj_addr_t address; + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned count; + const unsigned N_SPINS = 18; + + // We need to somehow check that addr is not NULL on the fast path. + // A very predictable + // branch on a register value is probably cheaper than dereferencing addr. + // We could also permanently lock the NULL entry in the hash table. + // But it's not clear that's cheaper either. + if (__builtin_expect(!addr, false)) + throw new java::lang::NullPointerException; + + JvAssert(!(addr & FLAGS)); +retry: + if (__builtin_expect(compare_and_swap(&(he -> address), + 0, addr),true)) + { + JvAssert(he -> light_thr_id == INVALID_THREAD_ID); + JvAssert(he -> light_count == 0); + he -> light_thr_id = self; + // Count fields are set correctly. Heavy_count was also zero, + // but can change asynchronously. + // This path is hopefully both fast and the most common. + LOG(ACQ_LIGHT, addr, self); + return; + } + address = he -> address; + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) + { + if (he -> light_thr_id == self) + { + // We hold the lightweight lock, and it's for the right + // address. + count = he -> light_count; + if (count == USHRT_MAX) + { + // I think most JVMs don't check for this. + // But I'm not convinced I couldn't turn this into a security + // hole, even with a 32 bit counter. + throw new java::lang::IllegalMonitorStateException( + JvNewStringLatin1("maximum monitor nesting level exceeded")); + } + he -> light_count = count + 1; + return; + } + else + { + JvAssert(!(address & LOCKED)); + // Lightweight lock is held, but by somone else. + // Spin a few times. This avoids turning this into a heavyweight + // lock if the current holder is about to release it. + // FIXME: Does this make sense on a uniprocessor, where + // it actually yields? It's probably cheaper to convert. + for (unsigned int i = 0; i < N_SPINS; ++i) + { + if ((he -> address & ~LOCKED) != address) goto retry; + spin(i); + } + if (!compare_and_swap(&(he -> address), address, address | LOCKED )) + { + wait_unlocked(he); + goto retry; + } + heavy_lock *hl = get_heavy(addr, he); + ++ (he -> heavy_count); + // The hl lock acquisition can't block for long, since it can + // only be held by other threads waiting for conversion, and + // they, like us, drop it quickly without blocking. + _Jv_MutexLock(&(hl->si.mutex)); + JvAssert(he -> address == address | LOCKED ); + release_set(&(he -> address), (address | REQUEST_CONVERSION | HEAVY)); + // release lock on he + LOG(REQ_CONV, (address | REQUEST_CONVERSION | HEAVY), self); + // If _Jv_CondWait is interrupted, we ignore the interrupt, but + // restore the thread's interrupt status flag when done. + jboolean interrupt_flag = false; + while ((he -> address & ~FLAGS) == (address & ~FLAGS)) + { + // Once converted, the lock has to retain heavyweight + // status, since heavy_count > 0. + int r = _Jv_CondWait (&(hl->si.condition), &(hl->si.mutex), 0, 0); + if (r == _JV_INTERRUPTED) + { + interrupt_flag = true; + Thread::currentThread()->interrupt_flag = false; + } + } + if (interrupt_flag) + Thread::currentThread()->interrupt_flag = interrupt_flag; + keep_live(addr); + // Guarantee that hl doesn't get unlinked by finalizer. + // This is only an issue if the client fails to release + // the lock, which is unlikely. + JvAssert(he -> address & HEAVY); + // Lock has been converted, we hold the heavyweight lock, + // heavy_count has been incremented. + return; + } + } + obj_addr_t was_heavy = (address & HEAVY); + if ((address & LOCKED) || + !compare_and_swap(&(he -> address), address, (address | LOCKED ))) + { + wait_unlocked(he); + goto retry; + } + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == 0) + { + // Either was_heavy is true, or something changed out from under us, + // since the initial test for 0 failed. + JvAssert(!(address & REQUEST_CONVERSION)); + // Can't convert a nonexistent lightweight lock. + heavy_lock *hl; + hl = (was_heavy? find_heavy(addr, he) : 0); + // The CAS succeeded, so was_heavy is still accurate. + if (0 == hl) + { + // It is OK to use the lighweight lock, since either the + // heavyweight lock does not exist, or none of the + // heavyweight locks are currently in use. Future threads + // trying to acquire the lock will see the lightweight + // one first and use that. + he -> light_thr_id = self; // OK, since nobody else can hold + // light lock or do this at the same time. + JvAssert(he -> light_count == 0); + JvAssert(was_heavy == (he -> address & HEAVY)); + release_set(&(he -> address), (addr | was_heavy)); + LOG(ACQ_LIGHT2, addr | was_heavy, self); + } + else + { + // Must use heavy lock. + ++ (he -> heavy_count); + JvAssert(0 == (address & ~HEAVY)); + release_set(&(he -> address), HEAVY); + LOG(ACQ_HEAVY, addr | was_heavy, self); + _Jv_MutexLock(&(hl->si.mutex)); + keep_live(addr); + } + return; + } + // Lightweight lock is held, but does not correspond to this object. + // We hold the lock on the hash entry, and he -> address can't + // change from under us. Neither can the chain of heavy locks. + { + JvAssert(0 == he -> heavy_count || (address & HEAVY)); + heavy_lock *hl = get_heavy(addr, he); + ++ (he -> heavy_count); + release_set(&(he -> address), address | HEAVY); + LOG(ACQ_HEAVY2, address | HEAVY, self); + _Jv_MutexLock(&(hl->si.mutex)); + keep_live(addr); + } +} + + +void +_Jv_MonitorExit (jobject obj) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + _Jv_ThreadId_t light_thr_id; + unsigned count; + obj_addr_t address; + +retry: + light_thr_id = he -> light_thr_id; + // Unfortunately, it turns out we always need to read the address + // first. Even if we are going to update it with compare_and_swap, + // we need to reset light_thr_id, and that's not safe unless we know + // that we hold the lock. + address = he -> address; + // First the (relatively) fast cases: + if (__builtin_expect(light_thr_id == self, true)) + // Above must fail if addr == 0 . + { + count = he -> light_count; + if (__builtin_expect((address & ~HEAVY) == addr, true)) + { + if (count != 0) + { + // We held the lightweight lock all along. Thus the values + // we saw for light_thr_id and light_count must have been valid. + he -> light_count = count - 1; + return; + } + else + { + // We hold the lightweight lock once. + he -> light_thr_id = INVALID_THREAD_ID; + if (compare_and_swap_release(&(he -> address), address, + address & HEAVY)) + { + LOG(REL_LIGHT, address & HEAVY, self); + return; + } + else + { + he -> light_thr_id = light_thr_id; // Undo prior damage. + goto retry; + } + } + } + // else lock is not for this address, conversion is requested, + // or the lock bit in the address field is set. + } + else + { + if (__builtin_expect(!addr, false)) + throw new java::lang::NullPointerException; + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Lightweight lock held by other thread\n\t" + "light_thr_id = 0x%lx, self = 0x%lx, " + "address = 0x%lx, heavy_count = %d, pid = %d\n", + light_thr_id, self, (unsigned long)address, + he -> heavy_count, getpid()); + print_he(he); + for(;;) {} +# endif + // Someone holds the lightweight lock for this object, and + // it can't be us. + throw new java::lang::IllegalMonitorStateException( + JvNewStringLatin1("current thread not owner")); + } + else + count = he -> light_count; + } + if (address & LOCKED) + { + wait_unlocked(he); + goto retry; + } + // Now the unlikely cases. + // We do know that: + // - Address is set, and doesn't contain the LOCKED bit. + // - If address refers to the same object as addr, then he -> light_thr_id + // refers to this thread, and count is valid. + // - The case in which we held the lightweight lock has been + // completely handled, except for the REQUEST_CONVERSION case. + // + if ((address & ~FLAGS) == addr) + { + // The lightweight lock is assigned to this object. + // Thus we must be in the REQUEST_CONVERSION case. + if (0 != count) + { + // Defer conversion until we exit completely. + he -> light_count = count - 1; + return; + } + JvAssert(he -> light_thr_id == self); + JvAssert(address & REQUEST_CONVERSION); + // Conversion requested + // Convert now. + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + goto retry; + heavy_lock *hl = find_heavy(addr, he); + JvAssert (0 != hl); + // Requestor created it. + he -> light_count = 0; + JvAssert(he -> heavy_count > 0); + // was incremented by requestor. + _Jv_MutexLock(&(hl->si.mutex)); + // Release the he lock after acquiring the mutex. + // Otherwise we can accidentally + // notify a thread that has already seen a heavyweight + // lock. + he -> light_thr_id = INVALID_THREAD_ID; + release_set(&(he -> address), HEAVY); + LOG(PROMOTE, address, self); + // lightweight lock now unused. + _Jv_CondNotifyAll(&(hl->si.condition), &(hl->si.mutex)); + _Jv_MutexUnlock(&(hl->si.mutex)); + // heavy_count was already incremented by original requestor. + keep_live(addr); + return; + } + // lightweight lock not for this object. + JvAssert(!(address & LOCKED)); + JvAssert((address & ~FLAGS) != addr); + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + goto retry; + heavy_lock *hl = find_heavy(addr, he); + if (NULL == hl) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Failed to find heavyweight lock for addr 0x%lx" + " pid = %d\n", addr, getpid()); + print_he(he); + for(;;) {} +# endif + release_set(&(he -> address), address); + throw new java::lang::IllegalMonitorStateException( + JvNewStringLatin1("current thread not owner")); + } + JvAssert(address & HEAVY); + count = he -> heavy_count; + JvAssert(count > 0); + --count; + he -> heavy_count = count; + if (0 == count) + { + const unsigned test_freq = 16; // Power of 2 + static volatile unsigned counter = 0; + unsigned my_counter = counter; + + counter = my_counter + 1; + if (my_counter%test_freq == 0) + { + // Randomize the interval length a bit. + counter = my_counter + (my_counter >> 4) % (test_freq/2); + // Unlock mutex first, to avoid self-deadlock, or worse. + _Jv_MutexUnlock(&(hl->si.mutex)); + maybe_remove_all_heavy(he, address &~HEAVY); + // release lock bit, preserving + // REQUEST_CONVERSION + // and object address. + } + else + { + release_set(&(he -> address), address &~HEAVY); + _Jv_MutexUnlock(&(hl->si.mutex)); + // Unlock after releasing the lock bit, so that + // we don't switch to another thread prematurely. + } + } + else + { + release_set(&(he -> address), address); + _Jv_MutexUnlock(&(hl->si.mutex)); + } + LOG(REL_HEAVY, addr, self); + keep_live(addr); +} + +// Return false if obj's monitor is held by the current thread +bool +_Jv_ObjectCheckMonitor (jobject obj) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)obj & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)obj; +#endif + obj_addr_t address; + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + + JvAssert(!(addr & FLAGS)); + address = he -> address; + // Try it the easy way first: + if (address == 0) return true; + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + if ((address & ~(HEAVY | REQUEST_CONVERSION)) == addr) + // Fails if entry is LOCKED. + // I can't asynchronously become or stop being the holder. + return he -> light_thr_id != self; +retry: + // Acquire the hash table entry lock + address &= ~LOCKED; + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + + bool not_mine; + + if ((address & ~FLAGS) == addr) + not_mine = (he -> light_thr_id != self); + else + { + heavy_lock* hl = find_heavy(addr, he); + not_mine = hl ? _Jv_MutexCheckMonitor(&hl->si.mutex) : true; + } + + release_set(&(he -> address), address); // unlock hash entry + return not_mine; +} + +// The rest of these are moderately thin veneers on _Jv_Cond ops. +// The current version of Notify might be able to make the pthread +// call AFTER releasing the lock, thus saving some context switches?? + +void +java::lang::Object::wait (jlong timeout, jint nanos) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)this; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + unsigned count; + obj_addr_t address; + heavy_lock *hl; + + if (__builtin_expect (timeout < 0 || nanos < 0 || nanos > 999999, false)) + throw new IllegalArgumentException; +retry: + address = he -> address; + address &= ~LOCKED; + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + // address did not have the lock bit set. We now hold the lock on he. + if ((address & ~FLAGS) == addr) + { + // Convert to heavyweight. + if (he -> light_thr_id != self) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Found wrong lightweight lock owner in wait " + "address = 0x%lx pid = %d\n", address, getpid()); + print_he(he); + for(;;) {} +# endif + release_set(&(he -> address), address); + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + } + count = he -> light_count; + hl = get_heavy(addr, he); + he -> light_count = 0; + he -> heavy_count += count + 1; + for (unsigned i = 0; i <= count; ++i) + _Jv_MutexLock(&(hl->si.mutex)); + // Again release the he lock after acquiring the mutex. + he -> light_thr_id = INVALID_THREAD_ID; + release_set(&(he -> address), HEAVY); // lightweight lock now unused. + LOG(PROMOTE2, addr, self); + if (address & REQUEST_CONVERSION) + _Jv_CondNotifyAll (&(hl->si.condition), &(hl->si.mutex)); + // Since we do this before we do a CondWait, we guarantee that + // threads waiting on requested conversion are awoken before + // a real wait on the same condition variable. + // No other notification can occur in the interim, since + // we hold the heavy lock, and notifications are made + // without acquiring it. + } + else /* We should hold the heavyweight lock. */ + { + hl = find_heavy(addr, he); + release_set(&(he -> address), address); + if (0 == hl) + { +# ifdef LOCK_DEBUG + fprintf(stderr, "Couldn't find heavy lock in wait " + "addr = 0x%lx pid = %d\n", addr, getpid()); + print_he(he); + for(;;) {} +# endif + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + } + JvAssert(address & HEAVY); + } + LOG(WAIT_START, addr, self); + switch (_Jv_CondWait (&(hl->si.condition), &(hl->si.mutex), timeout, nanos)) + { + case _JV_NOT_OWNER: + throw new IllegalMonitorStateException (JvNewStringLatin1 + ("current thread not owner")); + case _JV_INTERRUPTED: + if (Thread::interrupted ()) + throw new InterruptedException; + } + LOG(WAIT_END, addr, self); +} + +void +java::lang::Object::notify (void) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)this; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + heavy_lock *hl; + obj_addr_t address; + int result; + +retry: + address = ((he -> address) & ~LOCKED); + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + if ((address & ~FLAGS) == addr && he -> light_thr_id == self) + { + // We hold lightweight lock. Since it has not + // been inflated, there are no waiters. + release_set(&(he -> address), address); // unlock + return; + } + hl = find_heavy(addr, he); + // Hl can't disappear since we point to the underlying object. + // It's important that we release the lock bit before the notify, since + // otherwise we will try to wake up the target while we still hold the + // bit. This results in lock bit contention, which we don't handle + // terribly well. + release_set(&(he -> address), address); // unlock + if (0 == hl) + { + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); + return; + } + // We know that we hold the heavyweight lock at this point, + // and the lightweight lock is not in use. + result = _Jv_CondNotify(&(hl->si.condition), &(hl->si.mutex)); + LOG(NOTIFY, addr, self); + keep_live(addr); + if (__builtin_expect (result, 0)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +void +java::lang::Object::notifyAll (void) +{ +#ifdef JV_LINKER_CANNOT_8BYTE_ALIGN_STATICS + obj_addr_t addr = (obj_addr_t)this & ~((obj_addr_t)FLAGS); +#else + obj_addr_t addr = (obj_addr_t)this; +#endif + _Jv_ThreadId_t self = _Jv_ThreadSelf(); + unsigned hash = JV_SYNC_HASH(addr); + hash_entry * he = light_locks + hash; + heavy_lock *hl; + obj_addr_t address; + int result; + +retry: + address = (he -> address) & ~LOCKED; + if (!compare_and_swap(&(he -> address), address, address | LOCKED)) + { + wait_unlocked(he); + goto retry; + } + hl = find_heavy(addr, he); + if ((address & ~FLAGS) == addr && he -> light_thr_id == self) + { + // We hold lightweight lock. Since it has not + // been inflated, there are no waiters. + release_set(&(he -> address), address); // unlock + return; + } + release_set(&(he -> address), address); // unlock + if (0 == hl) + { + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); + } + result = _Jv_CondNotifyAll(&(hl->si.condition), &(hl->si.mutex)); + LOG(NOTIFY_ALL, addr, self); + if (__builtin_expect (result, 0)) + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("current thread not owner")); +} + +// This is declared in Java code and in Object.h. +// It should never be called with JV_HASH_SYNCHRONIZATION +void +java::lang::Object::sync_init (void) +{ + throw new IllegalMonitorStateException(JvNewStringLatin1 + ("internal error: sync_init")); +} + +// This is called on startup and declared in Object.h. +// For now we just make it a no-op. +void +_Jv_InitializeSyncMutex (void) +{ +} + +#endif /* JV_HASH_SYNCHRONIZATION */ + diff --git a/gcc-4.2.1/libjava/java/lang/natPosixProcess.cc b/gcc-4.2.1/libjava/java/lang/natPosixProcess.cc new file mode 100644 index 000000000..77ac69253 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natPosixProcess.cc @@ -0,0 +1,455 @@ +// natPosixProcess.cc - Native side of POSIX process code. + +/* Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif +#include <signal.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <pthread.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/lang/ConcreteProcess$ProcessManager.h> +#include <java/lang/ConcreteProcess.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InternalError.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Thread.h> +#include <java/io/File.h> +#include <java/io/FileDescriptor.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> +#include <java/io/FileInputStream.h> +#include <java/io/FileOutputStream.h> +#include <java/io/IOException.h> +#include <java/lang/OutOfMemoryError.h> + +using gnu::java::nio::channels::FileChannelImpl; + +extern char **environ; + +static char * +new_string (jstring string) +{ + jsize s = _Jv_GetStringUTFLength (string); + char *buf = (char *) _Jv_Malloc (s + 1); + _Jv_GetStringUTFRegion (string, 0, string->length(), buf); + buf[s] = '\0'; + return buf; +} + +static void +cleanup (char **args, char **env, char *path) +{ + if (args != NULL) + { + for (int i = 0; args[i] != NULL; ++i) + _Jv_Free (args[i]); + _Jv_Free (args); + } + if (env != NULL) + { + for (int i = 0; env[i] != NULL; ++i) + _Jv_Free (env[i]); + _Jv_Free (env); + } + if (path != NULL) + _Jv_Free (path); +} + +// This makes our error handling a bit simpler and it lets us avoid +// thread bugs where we close a possibly-reopened file descriptor for +// a second time. +static void +myclose (int &fd) +{ + if (fd != -1) + close (fd); + fd = -1; +} + +// There has to be a signal handler in order to be able to +// sigwait() on SIGCHLD. The information passed is ignored as it +// will be recovered by the waitpid() call. +static void +sigchld_handler (int) +{ + // Ignore. +} + + +// Get ready to enter the main reaper thread loop. +void +java::lang::ConcreteProcess$ProcessManager::init () +{ + using namespace java::lang; + // Remenber our PID so other threads can kill us. + reaperPID = (jlong) pthread_self (); + + // SIGCHLD is blocked in all threads in posix-threads.cc. + // Setup the SIGCHLD handler. + struct sigaction sa; + memset (&sa, 0, sizeof (sa)); + + sa.sa_handler = sigchld_handler; + // We only want signals when the things exit. + sa.sa_flags = SA_NOCLDSTOP; + + if (-1 == sigaction (SIGCHLD, &sa, NULL)) + goto error; + + // All OK. + return; + +error: + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::ConcreteProcess$ProcessManager::waitForSignal () +{ + // Wait for SIGCHLD + sigset_t mask; + pthread_sigmask (0, NULL, &mask); + sigdelset (&mask, SIGCHLD); + + // Use sigsuspend() instead of sigwait() as sigwait() doesn't play + // nicely with the GC's use of signals. + sigsuspend (&mask); + + // Do not check sigsuspend return value. The only legitimate return + // is EINTR, but there is a known kernel bug affecting alpha-linux + // wrt sigsuspend+handler+sigreturn that can result in a return value + // of __NR_sigsuspend and errno unset. Don't fail unnecessarily on + // older kernel versions. + + // All OK. + return; +} + +jboolean java::lang::ConcreteProcess$ProcessManager::reap () +{ + using namespace java::lang; + + pid_t pid; + + for (;;) + { + // Get the return code from a dead child process. + int status; + pid = waitpid ((pid_t) - 1, &status, WNOHANG); + if (pid == -1) + { + if (errno == ECHILD) + return false; + else + goto error; + } + + if (pid == 0) + return true; // No children to wait for. + + // Look up the process in our pid map. + ConcreteProcess * process = removeProcessFromMap ((jlong) pid); + + // Note that if process==NULL, then we have an unknown child. + // This is not common, but can happen, and isn't an error. + if (process) + { + JvSynchronize sync (process); + process->status = WIFEXITED (status) ? WEXITSTATUS (status) : -1; + process->state = ConcreteProcess::STATE_TERMINATED; + process->processTerminationCleanup(); + process->notifyAll (); + } + } + +error: + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::ConcreteProcess$ProcessManager::signalReaper () +{ + int c = pthread_kill ((pthread_t) reaperPID, SIGCHLD); + if (c == 0) + return; + // pthread_kill() failed. + throw new InternalError (JvNewStringUTF (strerror (c))); +} + +void +java::lang::ConcreteProcess::nativeDestroy () +{ + int c = kill ((pid_t) pid, SIGKILL); + if (c == 0) + return; + // kill() failed. + throw new InternalError (JvNewStringUTF (strerror (errno))); +} + +void +java::lang::ConcreteProcess::nativeSpawn () +{ + using namespace java::io; + + // Initialize all locals here to make cleanup simpler. + char **args = NULL; + char **env = NULL; + char *path = NULL; + int inp[2], outp[2], errp[2], msgp[2]; + inp[0] = -1; + inp[1] = -1; + outp[0] = -1; + outp[1] = -1; + errp[0] = -1; + errp[1] = -1; + msgp[0] = -1; + msgp[1] = -1; + errorStream = NULL; + inputStream = NULL; + outputStream = NULL; + + try + { + // Transform arrays to native form. + args = (char **) _Jv_Malloc ((progarray->length + 1) * sizeof (char *)); + + // Initialize so we can gracefully recover. + jstring *elts = elements (progarray); + for (int i = 0; i <= progarray->length; ++i) + args[i] = NULL; + + for (int i = 0; i < progarray->length; ++i) + args[i] = new_string (elts[i]); + args[progarray->length] = NULL; + + if (envp) + { + env = (char **) _Jv_Malloc ((envp->length + 1) * sizeof (char *)); + elts = elements (envp); + + // Initialize so we can gracefully recover. + for (int i = 0; i <= envp->length; ++i) + env[i] = NULL; + + for (int i = 0; i < envp->length; ++i) + env[i] = new_string (elts[i]); + env[envp->length] = NULL; + } + + // We allocate this here because we can't call malloc() after + // the fork. + if (dir != NULL) + path = new_string (dir->getPath ()); + + // Create pipes for I/O. MSGP is for communicating exec() + // status. + if (pipe (inp) || pipe (outp) || pipe (errp) || pipe (msgp) + || fcntl (msgp[1], F_SETFD, FD_CLOEXEC)) + throw new IOException (JvNewStringUTF (strerror (errno))); + + // We create the streams before forking. Otherwise if we had an + // error while creating the streams we would have run the child + // with no way to communicate with it. + errorStream = + new FileInputStream (new + FileChannelImpl (errp[0], FileChannelImpl::READ)); + inputStream = + new FileInputStream (new + FileChannelImpl (inp[0], FileChannelImpl::READ)); + outputStream = + new FileOutputStream (new FileChannelImpl (outp[1], + FileChannelImpl::WRITE)); + + // We don't use vfork() because that would cause the local + // environment to be set by the child. + + // Use temporary for fork result to avoid dirtying an extra page. + pid_t pid_tmp; + if ((pid_tmp = fork ()) == -1) + throw new IOException (JvNewStringUTF (strerror (errno))); + + if (pid_tmp == 0) + { + // Child process, so remap descriptors, chdir and exec. + if (envp) + { + // Preserve PATH and LD_LIBRARY_PATH unless specified + // explicitly. + char *path_val = getenv ("PATH"); + char *ld_path_val = getenv ("LD_LIBRARY_PATH"); + environ = env; + if (path_val && getenv ("PATH") == NULL) + { + char *path_env = + (char *) _Jv_Malloc (strlen (path_val) + 5 + 1); + strcpy (path_env, "PATH="); + strcat (path_env, path_val); + putenv (path_env); + } + if (ld_path_val && getenv ("LD_LIBRARY_PATH") == NULL) + { + char *ld_path_env = + (char *) _Jv_Malloc (strlen (ld_path_val) + 16 + 1); + strcpy (ld_path_env, "LD_LIBRARY_PATH="); + strcat (ld_path_env, ld_path_val); + putenv (ld_path_env); + } + } + + // We ignore errors from dup2 because they should never occur. + dup2 (outp[0], 0); + dup2 (inp[1], 1); + dup2 (errp[1], 2); + + // Use close and not myclose -- we're in the child, and we + // aren't worried about the possible race condition. + close (inp[0]); + close (inp[1]); + close (errp[0]); + close (errp[1]); + close (outp[0]); + close (outp[1]); + close (msgp[0]); + + // Change directory. + if (path != NULL) + { + if (chdir (path) != 0) + { + char c = errno; + write (msgp[1], &c, 1); + _exit (127); + } + } + // Make sure all file descriptors are closed. In + // multi-threaded programs, there is a race between when a + // descriptor is obtained, when we can set FD_CLOEXEC, and + // fork(). If the fork occurs before FD_CLOEXEC is set, the + // descriptor would leak to the execed process if we did not + // manually close it. So that is what we do. Since we + // close all the descriptors, it is redundant to set + // FD_CLOEXEC on them elsewhere. + int max_fd; +#ifdef HAVE_GETRLIMIT + rlimit rl; + int rv = getrlimit(RLIMIT_NOFILE, &rl); + if (rv == 0) + max_fd = rl.rlim_max - 1; + else + max_fd = 1024 - 1; +#else + max_fd = 1024 - 1; +#endif + while(max_fd > 2) + { + if (max_fd != msgp[1]) + close (max_fd); + max_fd--; + } + // Make sure that SIGCHLD is unblocked for the new process. + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGCHLD); + sigprocmask (SIG_UNBLOCK, &mask, NULL); + + execvp (args[0], args); + + // Send the parent notification that the exec failed. + char c = errno; + write (msgp[1], &c, 1); + _exit (127); + } + + // Parent. Close extra file descriptors and mark ours as + // close-on-exec. + pid = (jlong) pid_tmp; + + myclose (outp[0]); + myclose (inp[1]); + myclose (errp[1]); + myclose (msgp[1]); + + char c; + int r = read (msgp[0], &c, 1); + if (r == -1) + throw new IOException (JvNewStringUTF (strerror (errno))); + else if (r != 0) + throw new IOException (JvNewStringUTF (strerror (c))); + } + catch (java::lang::Throwable *thrown) + { + // Do some cleanup we only do on failure. If a stream object + // has been created, we must close the stream itself (to avoid + // duplicate closes when the stream object is collected). + // Otherwise we simply close the underlying file descriptor. + // We ignore errors here as they are uninteresting. + + try + { + if (inputStream != NULL) + inputStream->close (); + else + myclose (inp[0]); + } + catch (java::lang::Throwable *ignore) + { + } + + try + { + if (outputStream != NULL) + outputStream->close (); + else + myclose (outp[1]); + } + catch (java::lang::Throwable *ignore) + { + } + + try + { + if (errorStream != NULL) + errorStream->close (); + else + myclose (errp[0]); + } + catch (java::lang::Throwable *ignore) + { + } + + // These are potentially duplicate, but it doesn't matter due to + // the use of myclose. + myclose (outp[0]); + myclose (inp[1]); + myclose (errp[1]); + myclose (msgp[1]); + + exception = thrown; + } + + myclose (msgp[0]); + cleanup (args, env, path); +} diff --git a/gcc-4.2.1/libjava/java/lang/natRuntime.cc b/gcc-4.2.1/libjava/java/lang/natRuntime.cc new file mode 100644 index 000000000..a59ec4bad --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natRuntime.cc @@ -0,0 +1,319 @@ +// natRuntime.cc - Implementation of native side of Runtime class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-props.h> +#include <java-stack.h> +#include <java/lang/Long.h> +#include <java/lang/Runtime.h> +#include <java/lang/UnknownError.h> +#include <java/lang/UnsatisfiedLinkError.h> +#include <gnu/gcj/runtime/FinalizerThread.h> +#include <java/io/File.h> +#include <java/util/TimeZone.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/Process.h> +#include <java/lang/ConcreteProcess.h> +#include <java/lang/ClassLoader.h> + +#include <jni.h> + +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#include <errno.h> + +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif + +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif + + + +#ifdef USE_LTDL +#include <ltdl.h> + +/* FIXME: we don't always need this. The next libtool will let us use + AC_LTDL_PREOPEN to see if we do. */ +extern const lt_dlsymlist lt_preloaded_symbols[1] = { { 0, 0 } }; + +struct lookup_data +{ + const char *symname; + void *result; +}; + +static int +find_symbol (lt_dlhandle handle, lt_ptr data) +{ + lookup_data *ld = (lookup_data *) data; + ld->result = lt_dlsym (handle, ld->symname); + return ld->result != NULL; +} + +void * +_Jv_FindSymbolInExecutable (const char *symname) +{ + lookup_data data; + data.symname = symname; + data.result = NULL; + lt_dlforeach (find_symbol, (lt_ptr) &data); + return data.result; +} + +#else + +void * +_Jv_FindSymbolInExecutable (const char *) +{ + return NULL; +} + +#endif /* USE_LTDL */ + + + +void +java::lang::Runtime::runFinalizationForExit () +{ + if (finalizeOnExit) + _Jv_RunAllFinalizers (); +} + +void +java::lang::Runtime::exitInternal (jint status) +{ + // Make status right for Unix. This is perhaps strange. + if (status < 0 || status > 255) + status = 255; + + ::exit (status); +} + +jlong +java::lang::Runtime::freeMemory (void) +{ + return _Jv_GCFreeMemory (); +} + +void +java::lang::Runtime::gc (void) +{ + _Jv_RunGC (); +} + +#ifdef USE_LTDL +// List of names for JNI_OnLoad. +static const char *onload_names[] = _Jv_platform_onload_names; +#endif + +void +java::lang::Runtime::_load (jstring path, jboolean do_search) +{ + JvSynchronize sync (this); + using namespace java::lang; +#ifdef USE_LTDL + jint len = _Jv_GetStringUTFLength (path); + char buf[len + 1 + strlen (_Jv_platform_solib_prefix) + + strlen (_Jv_platform_solib_suffix)]; + int offset = 0; + if (do_search) + { + strcpy (buf, _Jv_platform_solib_prefix); + offset = strlen (_Jv_platform_solib_prefix); + } + jsize total = JvGetStringUTFRegion (path, 0, path->length(), &buf[offset]); + buf[offset + total] = '\0'; + + char *lib_name = buf; + + if (do_search) + { + ClassLoader *look = _Jv_StackTrace::GetFirstNonSystemClassLoader (); + + if (look != NULL) + { + // Don't include solib prefix in string passed to + // findLibrary. + jstring name = look->findLibrary(JvNewStringUTF(&buf[offset])); + if (name != NULL) + { + len = _Jv_GetStringUTFLength (name); + lib_name = (char *) _Jv_AllocBytes(len + 1); + total = JvGetStringUTFRegion (name, 0, + name->length(), lib_name); + lib_name[total] = '\0'; + // Don't append suffixes any more; we have the full file + // name. + do_search = false; + } + } + } + + lt_dlhandle h; + // FIXME: make sure path is absolute. + { + // Synchronize on java.lang.Class. This is to protect the class chain from + // concurrent modification by class registration calls which may be run + // during the dlopen(). + JvSynchronize sync (&java::lang::Class::class$); + h = do_search ? lt_dlopenext (lib_name) : lt_dlopen (lib_name); + } + if (h == NULL) + { + const char *msg = lt_dlerror (); + jstring str = JvNewStringLatin1 (lib_name); + str = str->concat (JvNewStringLatin1 (": ")); + str = str->concat (JvNewStringLatin1 (msg)); + throw new UnsatisfiedLinkError (str); + } + + // Search for JNI_OnLoad function. + void *onload = NULL; + const char **name = onload_names; + while (*name != NULL) + { + onload = lt_dlsym (h, *name); + if (onload != NULL) + break; + ++name; + } + + if (onload != NULL) + { + JavaVM *vm = _Jv_GetJavaVM (); + if (vm == NULL) + { + // FIXME: what? + return; + } + + // Push a new frame so that JNI_OnLoad will get the right class + // loader if it calls FindClass. + ::java::lang::ClassLoader *loader + = _Jv_StackTrace::GetFirstNonSystemClassLoader(); + JNIEnv *env = _Jv_GetJNIEnvNewFrameWithLoader (loader); + jint vers = ((jint (JNICALL *) (JavaVM *, void *)) onload) (vm, NULL); + _Jv_JNI_PopSystemFrame (env); + if (vers != JNI_VERSION_1_1 && vers != JNI_VERSION_1_2 + && vers != JNI_VERSION_1_4) + { + // FIXME: unload the library. + throw new UnsatisfiedLinkError (JvNewStringLatin1 ("unrecognized version from JNI_OnLoad")); + } + } +#else + throw new UnknownError + (JvNewStringLatin1 (do_search + ? "Runtime.loadLibrary not implemented" + : "Runtime.load not implemented")); +#endif /* USE_LTDL */ +} + +jboolean +java::lang::Runtime::loadLibraryInternal (jstring lib) +{ + JvSynchronize sync (this); + using namespace java::lang; +#ifdef USE_LTDL + jint len = _Jv_GetStringUTFLength (lib); + char buf[len + 1]; + jsize total = JvGetStringUTFRegion (lib, 0, lib->length(), buf); + buf[total] = '\0'; + // FIXME: make sure path is absolute. + lt_dlhandle h = lt_dlopenext (buf); + return h != NULL; +#else + return false; +#endif /* USE_LTDL */ +} + +void +java::lang::Runtime::init (void) +{ +#ifdef USE_LTDL + lt_dlinit (); + // Set module load path. + lt_dlsetsearchpath (_Jv_Module_Load_Path); + // Make sure self is opened. + lt_dlopen (NULL); +#endif +} + +void +java::lang::Runtime::runFinalization (void) +{ + gnu::gcj::runtime::FinalizerThread::finalizerReady (); +} + +jlong +java::lang::Runtime::totalMemory (void) +{ + return _Jv_GCTotalMemory (); +} + +jlong +java::lang::Runtime::maxMemory (void) +{ + // We don't have a maximum. FIXME: we might if we ask the GC for + // one. + return Long::MAX_VALUE; +} + +void +java::lang::Runtime::traceInstructions (jboolean) +{ + // Do nothing. +} + +void +java::lang::Runtime::traceMethodCalls (jboolean) +{ + // Do nothing. +} + +java::lang::Process * +java::lang::Runtime::execInternal (jstringArray cmd, + jstringArray env, + java::io::File *dir) +{ + return new java::lang::ConcreteProcess (cmd, env, dir); +} + +jint +java::lang::Runtime::availableProcessors (void) +{ + // FIXME: find the real value. + return 1; +} + +jstring +java::lang::Runtime::nativeGetLibname (jstring pathname, jstring libname) +{ + java::lang::StringBuffer *sb = new java::lang::StringBuffer (); + sb->append(pathname); + if (pathname->length() > 0) + sb->append (_Jv_platform_file_separator); + + sb->append (JvNewStringLatin1 (_Jv_platform_solib_prefix)); + sb->append(libname); + sb->append (JvNewStringLatin1 (_Jv_platform_solib_suffix)); + + return sb->toString(); +} diff --git a/gcc-4.2.1/libjava/java/lang/natString.cc b/gcc-4.2.1/libjava/java/lang/natString.cc new file mode 100644 index 000000000..495a356a1 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natString.cc @@ -0,0 +1,1044 @@ +// natString.cc - Implementation of java.lang.String native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <string.h> +#include <stdlib.h> + +#include <gcj/cni.h> +#include <java/lang/Character.h> +#include <java/lang/CharSequence.h> +#include <java/lang/String.h> +#include <java/lang/IndexOutOfBoundsException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/StringIndexOutOfBoundsException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/StringBuffer.h> +#include <java/io/ByteArrayOutputStream.h> +#include <java/io/OutputStreamWriter.h> +#include <java/io/ByteArrayInputStream.h> +#include <java/io/InputStreamReader.h> +#include <java/util/Locale.h> +#include <gnu/gcj/convert/UnicodeToBytes.h> +#include <gnu/gcj/convert/BytesToUnicode.h> +#include <gnu/gcj/runtime/StringBuffer.h> +#include <jvm.h> + +static jstring* strhash = NULL; +static int strhash_count = 0; /* Number of slots used in strhash. */ +static int strhash_size = 0; /* Number of slots available in strhash. + * Assumed be power of 2! */ + +// Some defines used by toUpperCase / toLowerCase. +#define ESSET 0x00df +#define CAPITAL_S 0x0053 +#define SMALL_I 0x0069 +#define CAPITAL_I_WITH_DOT 0x0130 +#define SMALL_DOTLESS_I 0x0131 +#define CAPITAL_I 0x0049 + +#define DELETED_STRING ((jstring)(~0)) +#define SET_STRING_IS_INTERNED(STR) /* nothing */ + +#define UNMASK_PTR(Ptr) (((unsigned long) (Ptr)) & ~0x01) +#define MASK_PTR(Ptr) (((unsigned long) (Ptr)) | 0x01) +#define PTR_MASKED(Ptr) (((unsigned long) (Ptr)) & 0x01) + +/* Find a slot where the string with elements DATA, length LEN, + and hash HASH should go in the strhash table of interned strings. */ +jstring* +_Jv_StringFindSlot (jchar* data, jint len, jint hash) +{ + JvSynchronize sync (&java::lang::String::class$); + + int start_index = hash & (strhash_size - 1); + int deleted_index = -1; + + int index = start_index; + /* step must be non-zero, and relatively prime with strhash_size. */ + jint step = (hash ^ (hash >> 16)) | 1; + do + { + jstring* ptr = &strhash[index]; + jstring value = (jstring) UNMASK_PTR (*ptr); + if (value == NULL) + { + if (deleted_index >= 0) + return (&strhash[deleted_index]); + else + return ptr; + } + else if (*ptr == DELETED_STRING) + deleted_index = index; + else if (value->length() == len + && memcmp(JvGetStringChars(value), data, 2*len) == 0) + return (ptr); + index = (index + step) & (strhash_size - 1); + } + while (index != start_index); + // Note that we can have INDEX == START_INDEX if the table has no + // NULL entries but does have DELETED_STRING entries. + JvAssert (deleted_index >= 0); + return &strhash[deleted_index]; +} + +/* Calculate a hash code for the string starting at PTR at given LENGTH. + This uses the same formula as specified for java.lang.String.hash. */ + +static jint +hashChars (jchar* ptr, jint length) +{ + jchar* limit = ptr + length; + jint hash = 0; + // Updated specification from + // http://www.javasoft.com/docs/books/jls/clarify.html. + while (ptr < limit) + hash = (31 * hash) + *ptr++; + return hash; +} + +jint +java::lang::String::hashCode() +{ + if (cachedHashCode == 0) + cachedHashCode = hashChars(JvGetStringChars(this), length()); + return cachedHashCode; +} + +jstring* +_Jv_StringGetSlot (jstring str) +{ + jchar* data = JvGetStringChars(str); + int length = str->length(); + return _Jv_StringFindSlot(data, length, hashChars (data, length)); +} + +static void +rehash () +{ + JvSynchronize sync (&java::lang::String::class$); + + if (strhash == NULL) + { + strhash_size = 1024; + strhash = (jstring *) _Jv_AllocBytes (strhash_size * sizeof (jstring)); + } + else + { + int i = strhash_size; + jstring* ptr = strhash + i; + int nsize = strhash_size * 2; + jstring *next = (jstring *) _Jv_AllocBytes (nsize * sizeof (jstring)); + + while (--i >= 0) + { + --ptr; + if (*ptr == NULL || *ptr == DELETED_STRING) + continue; + + /* This is faster equivalent of + * *__JvGetInternSlot(*ptr) = *ptr; */ + jstring val = (jstring) UNMASK_PTR (*ptr); + jint hash = val->hashCode(); + jint index = hash & (nsize - 1); + jint step = (hash ^ (hash >> 16)) | 1; + for (;;) + { + if (next[index] == NULL) + { + next[index] = *ptr; + break; + } + index = (index + step) & (nsize - 1); + } + } + + strhash_size = nsize; + strhash = next; + } +} + +jstring +java::lang::String::intern() +{ + JvSynchronize sync (&java::lang::String::class$); + if (3 * strhash_count >= 2 * strhash_size) + rehash(); + jstring* ptr = _Jv_StringGetSlot(this); + if (*ptr != NULL && *ptr != DELETED_STRING) + { + // See description in _Jv_FinalizeString() to understand this. + *ptr = (jstring) MASK_PTR (*ptr); + return (jstring) UNMASK_PTR (*ptr); + } + jstring str = (this->data == this + ? this + : _Jv_NewString(JvGetStringChars(this), this->length())); + SET_STRING_IS_INTERNED(str); + strhash_count++; + *ptr = str; + // When string is GC'd, clear the slot in the hash table. + _Jv_RegisterStringFinalizer (str); + return str; +} + +// The fake String finalizer. This is only used when the String has +// been intern()d. However, we must check this case, as it might be +// called by the Reference code for any String. +void +_Jv_FinalizeString (jobject obj) +{ + JvSynchronize sync (&java::lang::String::class$); + + // We might not actually have intern()d any strings at all, if + // we're being called from Reference. + if (! strhash) + return; + + jstring str = reinterpret_cast<jstring> (obj); + jstring *ptr = _Jv_StringGetSlot(str); + if (*ptr == NULL || *ptr == DELETED_STRING + || (jobject) UNMASK_PTR (*ptr) != obj) + return; + + // We assume the lowest bit of the pointer is free for our nefarious + // manipulations. What we do is set it to `0' (implicitly) when + // interning the String. If we subsequently re-intern the same + // String, then we set the bit. When finalizing, if the bit is set + // then we clear it and re-register the finalizer. We know this is + // a safe approach because both intern() and _Jv_FinalizeString() + // acquire the class lock; this bit can't be manipulated when the + // lock is not held. So if we are finalizing and the bit is clear + // then we know all references are gone and we can clear the entry + // in the hash table. The naive approach of simply clearing the + // pointer here fails in the case where a request to intern a new + // string with the same contents is made between the time the + // intern()d string is found to be unreachable and when the + // finalizer is actually run. In this case we could clear a pointer + // to a valid string, and future intern() calls for that particular + // value would spuriously fail. + if (PTR_MASKED (*ptr)) + { + *ptr = (jstring) UNMASK_PTR (*ptr); + _Jv_RegisterStringFinalizer (obj); + } + else + { + *ptr = DELETED_STRING; + strhash_count--; + } +} + +jstring +_Jv_NewStringUTF (const char *bytes) +{ + int size = strlen (bytes); + unsigned char *p = (unsigned char *) bytes; + + int length = _Jv_strLengthUtf8 ((char *) p, size); + if (length < 0) + return NULL; + + jstring jstr = JvAllocString (length); + jchar *chrs = JvGetStringChars (jstr); + + p = (unsigned char *) bytes; + unsigned char *limit = p + size; + while (p < limit) + *chrs++ = UTF8_GET (p, limit); + + return jstr; +} + +jstring +_Jv_NewStringUtf8Const (Utf8Const* str) +{ + jchar *chrs; + jchar buffer[100]; + jstring jstr; + unsigned char* data = (unsigned char*) str->data; + unsigned char* limit = data + str->length; + int length = _Jv_strLengthUtf8(str->data, str->length); + + if (length <= (int) (sizeof(buffer) / sizeof(jchar))) + { + jstr = NULL; + chrs = buffer; + } + else + { + jstr = JvAllocString(length); + chrs = JvGetStringChars(jstr); + } + + jint hash = 0; + while (data < limit) + { + jchar ch = UTF8_GET(data, limit); + hash = (31 * hash) + ch; + *chrs++ = ch; + } + chrs -= length; + + JvSynchronize sync (&java::lang::String::class$); + if (3 * strhash_count >= 2 * strhash_size) + rehash(); + jstring* ptr = _Jv_StringFindSlot (chrs, length, hash); + if (*ptr != NULL && *ptr != DELETED_STRING) + return (jstring) UNMASK_PTR (*ptr); + strhash_count++; + if (jstr == NULL) + { + jstr = JvAllocString(length); + chrs = JvGetStringChars(jstr); + memcpy (chrs, buffer, sizeof(jchar)*length); + } + jstr->cachedHashCode = hash; + *ptr = jstr; + SET_STRING_IS_INTERNED(jstr); + // When string is GC'd, clear the slot in the hash table. Note that + // we don't have to call _Jv_RegisterStringFinalizer here, as we + // know the new object cannot be referred to by a Reference. + _Jv_RegisterFinalizer ((void *) jstr, _Jv_FinalizeString); + return jstr; +} + +jsize +_Jv_GetStringUTFLength (jstring string) +{ + jsize len = 0; + jchar *ptr = JvGetStringChars (string); + jsize i = string->length(); + while (--i >= 0) + { + jchar ch = *ptr++; + if (ch > 0 && ch <= 0x7F) + len += 1; + else if (ch <= 0x7FF) + len += 2; + else + len += 3; + } + return len; +} + +// Not sure this quite matches GetStringUTFRegion. +// null-termination of result? len? throw exception? +jsize +_Jv_GetStringUTFRegion (jstring str, jsize start, jsize len, char *buf) +{ + jchar *sptr = JvGetStringChars (str) + start; + jsize i = len; + char *dptr = buf; + while (--i >= 0) + { + jchar ch = *sptr++; + if (ch > 0 && ch <= 0x7F) + *dptr++ = (char) ch; + else if (ch <= 0x7FF) + { + *dptr++ = (char) (0xC0 + ((ch >> 6) & 0x1F)); + *dptr++ = (char) (0x80 + (ch & 0x3F)); + } + else + { + *dptr++ = (char) (0xE0 + ((ch >> 12) & 0xF)); + *dptr++ = (char) (0x80 + ((ch >> 6) & 0x3F)); + *dptr++ = (char) (0x80 + (ch & 0x3F)); + } + } + return dptr - buf; +} + +/* Put printed (decimal) representation of NUM in a buffer. + BUFEND marks the end of the buffer, which must be at least 11 jchars long. + Returns the COUNT of jchars written. The result is in + (BUFEND - COUNT) (inclusive) upto (BUFEND) (exclusive). */ + +jint +_Jv_FormatInt (jchar* bufend, jint num) +{ + register jchar* ptr = bufend; + jboolean isNeg; + if (num < 0) + { + isNeg = true; + if (num != (jint) -2147483648U) + num = -(num); + else + { + // Handle special case of MIN_VALUE. + *--ptr = '8'; + num = 214748364; + } + } + else + isNeg = false; + + do + { + *--ptr = (jchar) ((int) '0' + (num % 10)); + num /= 10; + } + while (num > 0); + + if (isNeg) + *--ptr = '-'; + return bufend - ptr; +} + +jstring +java::lang::String::valueOf (jint num) +{ + // Use an array large enough for "-2147483648"; i.e. 11 chars. + jchar buffer[11]; + int i = _Jv_FormatInt (buffer+11, num); + return _Jv_NewString (buffer+11-i, i); +} + +jstring +_Jv_NewString(const jchar *chars, jsize len) +{ + jstring str = _Jv_AllocString(len); + jchar* data = JvGetStringChars (str); + memcpy (data, chars, len * sizeof (jchar)); + return str; +} + +jstring +_Jv_NewStringLatin1(const char *bytes, jsize len) +{ + jstring str = JvAllocString(len); + jchar* data = JvGetStringChars (str); + while (--len >= 0) + *data++ = *(unsigned char*)bytes++; + return str; +} + +void +java::lang::String::init(jcharArray chars, jint offset, jint count, + jboolean dont_copy) +{ + if (! chars) + throw new NullPointerException; + jsize data_size = JvGetArrayLength (chars); + if (offset < 0 || count < 0 || offset + count < 0 + || offset + count > data_size) + throw new ArrayIndexOutOfBoundsException; + jcharArray array; + jchar *pdst; + if (! dont_copy) + { + array = JvNewCharArray(count); + pdst = elements (array); + memcpy (pdst, elements (chars) + offset, count * sizeof (jchar)); + } + else + { + array = chars; + pdst = &(elements(array)[offset]); + } + + data = array; + boffset = (char *) pdst - (char *) array; + this->count = count; +} + +void +java::lang::String::init(jbyteArray ascii, jint hibyte, jint offset, + jint count) +{ + if (! ascii) + throw new NullPointerException; + jsize data_size = JvGetArrayLength (ascii); + if (offset < 0 || count < 0 || offset + count < 0 + || offset + count > data_size) + throw new ArrayIndexOutOfBoundsException; + jcharArray array = JvNewCharArray(count); + jbyte *psrc = elements (ascii) + offset; + jchar *pdst = elements (array); + data = array; + boffset = (char *) pdst - (char *) array; + this->count = count; + hibyte = (hibyte & 0xff) << 8; + while (-- count >= 0) + { + *pdst++ = hibyte | (*psrc++ & 0xff); + } +} + +void +java::lang::String::init (jbyteArray bytes, jint offset, jint count, + jstring encoding) +{ + if (! bytes) + throw new NullPointerException; + jsize data_size = JvGetArrayLength (bytes); + if (offset < 0 || count < 0 || offset + count < 0 + || offset + count > data_size) + throw new ArrayIndexOutOfBoundsException; + jcharArray array = JvNewCharArray (count); + gnu::gcj::convert::BytesToUnicode *converter + = gnu::gcj::convert::BytesToUnicode::getDecoder(encoding); + jint outpos = 0; + int avail = count; + converter->setInput(bytes, offset, offset+count); + while (converter->inpos < converter->inlength) + { + int done = converter->read(array, outpos, avail); + if (done == 0) + { + jint new_size = 2 * (outpos + avail); + jcharArray new_array = JvNewCharArray (new_size); + memcpy (elements (new_array), elements (array), + outpos * sizeof(jchar)); + array = new_array; + avail = new_size - outpos; + } + else + { + outpos += done; + avail -= done; + } + } + converter->done (); + this->data = array; + this->boffset = (char *) elements (array) - (char *) array; + this->count = outpos; +} + +void +java::lang::String::init (gnu::gcj::runtime::StringBuffer *buffer) +{ + init (buffer->value, 0, buffer->count, true); +} + +jboolean +java::lang::String::equals(jobject anObject) +{ + if (anObject == NULL) + return false; + if (anObject == this) + return true; + if (anObject->getClass() != &java::lang::String::class$) + return false; + jstring other = (jstring) anObject; + if (count != other->count) + return false; + + // If both have cached hash codes, check that. If the cached hash + // codes are zero, don't bother trying to compute them. + int myHash = cachedHashCode; + int otherHash = other->cachedHashCode; + if (myHash && otherHash && myHash != otherHash) + return false; + + // We could see if both are interned, and return false. But that + // seems too expensive. + + jchar *xptr = JvGetStringChars (this); + jchar *yptr = JvGetStringChars (other); + return ! memcmp (xptr, yptr, count * sizeof (jchar)); +} + +jboolean +java::lang::String::contentEquals(java::lang::StringBuffer* buffer) +{ + if (buffer == NULL) + throw new NullPointerException; + JvSynchronize sync(buffer); + if (count != buffer->count) + return false; + if (data == buffer->value) + return true; // Possible if shared. + jchar *xptr = JvGetStringChars(this); + jchar *yptr = elements(buffer->value); + return ! memcmp (xptr, yptr, count * sizeof (jchar)); +} + +jboolean +java::lang::String::contentEquals(java::lang::CharSequence *seq) +{ + if (seq->length() != count) + return false; + jchar *value = JvGetStringChars(this); + for (int i = 0; i < count; ++i) + if (value[i] != seq->charAt(i)) + return false; + return true; +} + +jchar +java::lang::String::charAt(jint i) +{ + if (i < 0 || i >= count) + throw new java::lang::StringIndexOutOfBoundsException(i); + return JvGetStringChars(this)[i]; +} + +void +java::lang::String::getChars(jint srcBegin, jint srcEnd, + jcharArray dst, jint dstBegin) +{ + jint dst_length = JvGetArrayLength (dst); + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) + throw new java::lang::StringIndexOutOfBoundsException; + // The 2nd part of the test below is equivalent to + // dstBegin + (srcEnd-srcBegin) > dst_length + // except that it does not overflow. + if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin)) + throw new ArrayIndexOutOfBoundsException; + jchar *dPtr = elements (dst) + dstBegin; + jchar *sPtr = JvGetStringChars (this) + srcBegin; + jint i = srcEnd - srcBegin; + memcpy (dPtr, sPtr, i * sizeof (jchar)); +} + +jbyteArray +java::lang::String::getBytes (jstring enc) +{ + jint todo = length(); + jint buflen = todo; + jbyteArray buffer = JvNewByteArray(todo); + jint bufpos = 0; + jint offset = 0; + gnu::gcj::convert::UnicodeToBytes *converter + = gnu::gcj::convert::UnicodeToBytes::getEncoder(enc); + while (todo > 0 || converter->havePendingBytes()) + { + converter->setOutput(buffer, bufpos); + // We only really need to do a single write. + converter->setFinished(); + int converted = converter->write(this, offset, todo, NULL); + bufpos = converter->count; + if (converted == 0 && bufpos == converter->count) + { + buflen *= 2; + jbyteArray newbuffer = JvNewByteArray(buflen); + memcpy (elements (newbuffer), elements (buffer), bufpos); + buffer = newbuffer; + } + else + bufpos = converter->count; + + offset += converted; + todo -= converted; + } + converter->done (); + if (bufpos == buflen) + return buffer; + jbyteArray result = JvNewByteArray(bufpos); + memcpy (elements (result), elements (buffer), bufpos); + return result; +} + +void +java::lang::String::getBytes(jint srcBegin, jint srcEnd, + jbyteArray dst, jint dstBegin) +{ + jint dst_length = JvGetArrayLength (dst); + if (srcBegin < 0 || srcBegin > srcEnd || srcEnd > count) + throw new java::lang::StringIndexOutOfBoundsException; + // The 2nd part of the test below is equivalent to + // dstBegin + (srcEnd-srcBegin) > dst_length + // except that it does not overflow. + if (dstBegin < 0 || dstBegin > dst_length - (srcEnd-srcBegin)) + throw new ArrayIndexOutOfBoundsException; + jbyte *dPtr = elements (dst) + dstBegin; + jchar *sPtr = JvGetStringChars (this) + srcBegin; + jint i = srcEnd-srcBegin; + while (--i >= 0) + *dPtr++ = (jbyte) *sPtr++; +} + +jcharArray +java::lang::String::toCharArray() +{ + jcharArray array = JvNewCharArray(count); + jchar *dPtr = elements (array); + jchar *sPtr = JvGetStringChars (this); + jint i = count; + memcpy (dPtr, sPtr, i * sizeof (jchar)); + return array; +} + +jboolean +java::lang::String::equalsIgnoreCase (jstring anotherString) +{ + if (anotherString == NULL || count != anotherString->count) + return false; + jchar *tptr = JvGetStringChars (this); + jchar *optr = JvGetStringChars (anotherString); + jint i = count; + while (--i >= 0) + { + jchar tch = *tptr++; + jchar och = *optr++; + if (tch != och + && (java::lang::Character::toLowerCase (tch) + != java::lang::Character::toLowerCase (och)) + && (java::lang::Character::toUpperCase (tch) + != java::lang::Character::toUpperCase (och))) + return false; + } + return true; +} + +jboolean +java::lang::String::regionMatches (jint toffset, + jstring other, jint ooffset, jint len) +{ + if (toffset < 0 || ooffset < 0 || len < 0 + || toffset > count - len + || ooffset > other->count - len) + return false; + jchar *tptr = JvGetStringChars (this) + toffset; + jchar *optr = JvGetStringChars (other) + ooffset; + jint i = len; + return ! memcmp (tptr, optr, i * sizeof (jchar)); +} + +jint +java::lang::String::compareTo (jstring anotherString) +{ + jchar *tptr = JvGetStringChars (this); + jchar *optr = JvGetStringChars (anotherString); + jint tlen = this->count; + jint olen = anotherString->count; + jint i = tlen > olen ? olen : tlen; + while (--i >= 0) + { + jchar tch = *tptr++; + jchar och = *optr++; + if (tch != och) + return (jint) tch - (jint) och; + } + return tlen - olen; +} + +jboolean +java::lang::String::regionMatches (jboolean ignoreCase, jint toffset, + jstring other, jint ooffset, jint len) +{ + if (toffset < 0 || ooffset < 0 || len < 0 + || toffset > count - len + || ooffset > other->count - len) + return false; + jchar *tptr = JvGetStringChars (this) + toffset; + jchar *optr = JvGetStringChars (other) + ooffset; + jint i = len; + if (ignoreCase) + { + while (--i >= 0) + { + jchar tch = *tptr++; + jchar och = *optr++; + if ((java::lang::Character::toLowerCase (tch) + != java::lang::Character::toLowerCase (och)) + && (java::lang::Character::toUpperCase (tch) + != java::lang::Character::toUpperCase (och))) + return false; + } + return true; + } + return ! memcmp (tptr, optr, i * sizeof (jchar)); +} + +jboolean +java::lang::String::startsWith (jstring prefix, jint toffset) +{ + jint i = prefix->count; + if (toffset < 0 || toffset > count - i) + return false; + jchar *xptr = JvGetStringChars (this) + toffset; + jchar *yptr = JvGetStringChars (prefix); + return ! memcmp (xptr, yptr, i * sizeof (jchar)); +} + +jint +java::lang::String::indexOf (jint ch, jint fromIndex) +{ + if (fromIndex < 0) + fromIndex = 0; + jchar *ptr = JvGetStringChars(this); + for (;; ++fromIndex) + { + if (fromIndex >= count) + return -1; + if (ptr[fromIndex] == ch) + return fromIndex; + } +} + +jint +java::lang::String::indexOf (jstring s, jint fromIndex) +{ + const jchar *const xchars = JvGetStringChars(s); + const jchar *const ychars = JvGetStringChars(this) + fromIndex; + + const int xlength = s->length (); + const int ylength = length () - fromIndex; + + int i = 0; + int j = 0; + + while (i < ylength && j < xlength) + { + if (xchars[j] != ychars[i]) + { + i = i - j + 1; + j = 0; + } + else + i++, j++; + } + + if (j >= xlength) + return fromIndex + i - xlength; + else + return -1; +} + +jint +java::lang::String::lastIndexOf (jint ch, jint fromIndex) +{ + if (fromIndex >= count) + fromIndex = count - 1; + jchar *ptr = JvGetStringChars(this); + for (;; --fromIndex) + { + if (fromIndex < 0) + return -1; + if (ptr[fromIndex] == ch) + return fromIndex; + } +} + +jstring +java::lang::String::substring (jint beginIndex, jint endIndex) +{ + if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) + throw new StringIndexOutOfBoundsException; + if (beginIndex == 0 && endIndex == count) + return this; + jint newCount = endIndex - beginIndex; + // For very small strings, just allocate a new one. For other + // substrings, allocate a new one unless the substring is over half + // of the original string. + if (newCount <= 8 || newCount < (count >> 1)) + return JvNewString(JvGetStringChars(this) + beginIndex, newCount); + jstring s = new String(); + s->data = data; + s->count = newCount; + s->boffset = boffset + sizeof(jchar) * beginIndex; + return s; +} + +jstring +java::lang::String::concat(jstring str) +{ + jint str_count = str->count; + if (str_count == 0) + return this; + jstring result = JvAllocString(count + str_count); + jchar *dstPtr = JvGetStringChars(result); + jchar *srcPtr = JvGetStringChars(this); + jint i = count; + memcpy (dstPtr, srcPtr, i * sizeof (jchar)); + dstPtr += i; + srcPtr = JvGetStringChars(str); + i = str->count; + memcpy (dstPtr, srcPtr, i * sizeof (jchar)); + return result; +} + +jstring +java::lang::String::replace (jchar oldChar, jchar newChar) +{ + jint i; + jchar* chrs = JvGetStringChars (this); + for (i = 0; ; i++) + { + if (i == count) + return this; + if (chrs[i] == oldChar) + break; + } + jstring result = JvAllocString (count); + jchar *dPtr = JvGetStringChars (result); + for (int j = 0; j < i; j++) + *dPtr++ = chrs[j]; + for (; i < count; i++) + { + jchar ch = chrs[i]; + if (ch == oldChar) + ch = newChar; + *dPtr++ = ch; + } + return result; +} + +jstring +java::lang::String::toLowerCase (java::util::Locale *locale) +{ + jint i; + jchar* chrs = JvGetStringChars(this); + jchar ch = 0; + + bool handle_tr = false; + if (locale != NULL) + { + String *lang = locale->getLanguage (); + if (lang->length () == 2 + && lang->charAt (0) == 't' + && lang->charAt (1) == 'r') + handle_tr = true; + } + + for (i = 0; ; i++) + { + if (i == count) + return this; + jchar origChar = chrs[i]; + + if (handle_tr && (origChar == CAPITAL_I + || origChar == CAPITAL_I_WITH_DOT)) + break; + + ch = java::lang::Character::toLowerCase(origChar); + if (ch != origChar) + break; + } + jstring result = JvAllocString(count); + jchar *dPtr = JvGetStringChars (result); + for (int j = 0; j < i; j++) + *dPtr++ = chrs[j]; + *dPtr++ = ch; i++; + for (; i < count; i++) + { + if (handle_tr && chrs[i] == CAPITAL_I) + *dPtr++ = SMALL_DOTLESS_I; + else if (handle_tr && chrs[i] == CAPITAL_I_WITH_DOT) + *dPtr++ = SMALL_I; + else + *dPtr++ = java::lang::Character::toLowerCase(chrs[i]); + } + return result; +} + +jstring +java::lang::String::toUpperCase (java::util::Locale *locale) +{ + jint i; + jchar* chrs = JvGetStringChars(this); + jchar ch; + + // When handling a specific locale there might be special rules. + // Currently all existing rules are simply handled inline, as there + // are only two and they are documented in the online 1.2 docs. + bool handle_esset = locale != NULL; + bool handle_tr = false; + if (locale != NULL) + { + String *lang = locale->getLanguage (); + if (lang->length () == 2 + && lang->charAt (0) == 't' + && lang->charAt (1) == 'r') + handle_tr = true; + } + + int new_count = count; + bool new_string = false; + for (i = 0; ; i++) + { + if (i == count) + break; + jchar origChar = chrs[i]; + + if (handle_esset && origChar == ESSET) + { + ++new_count; + new_string = true; + } + else if (handle_tr && (origChar == SMALL_I + || origChar == SMALL_DOTLESS_I)) + new_string = true; + else + { + ch = java::lang::Character::toUpperCase(origChar); + if (ch != origChar) + new_string = true; + } + + if (new_string && ! handle_esset) + break; + } + if (! new_string) + return this; + jstring result = JvAllocString(new_count); + jchar *dPtr = JvGetStringChars (result); + for (i = 0; i < count; i++) + { + if (handle_esset && chrs[i] == ESSET) + { + *dPtr++ = CAPITAL_S; + *dPtr++ = CAPITAL_S; + } + else if (handle_tr && chrs[i] == SMALL_I) + *dPtr++ = CAPITAL_I_WITH_DOT; + else if (handle_tr && chrs[i] == SMALL_DOTLESS_I) + *dPtr++ = CAPITAL_I; + else + *dPtr++ = java::lang::Character::toUpperCase(chrs[i]); + } + return result; +} + +jstring +java::lang::String::trim () +{ + jchar* chrs = JvGetStringChars(this); + if (count == 0 || (chrs[0] > ' ' && chrs[count-1] > ' ')) + return this; + jint preTrim = 0; + for (;; preTrim++) + { + if (preTrim == count) + return new String(); + if (chrs[preTrim] > ' ') + break; + } + jint endTrim = count; + while (chrs[endTrim-1] <= ' ') + endTrim--; + return substring(preTrim, endTrim); +} + +jstring +java::lang::String::valueOf(jcharArray data, jint offset, jint count) +{ + jint data_length = JvGetArrayLength (data); + if (offset < 0 || count < 0 || offset > data_length - count) + throw new ArrayIndexOutOfBoundsException; + jstring result = JvAllocString(count); + jchar *sPtr = elements (data) + offset; + jchar *dPtr = JvGetStringChars(result); + memcpy (dPtr, sPtr, count * sizeof (jchar)); + return result; +} + +jstring +java::lang::String::valueOf(jchar c) +{ + jstring result = JvAllocString(1); + JvGetStringChars (result)[0] = c; + return result; +} diff --git a/gcc-4.2.1/libjava/java/lang/natStringBuffer.cc b/gcc-4.2.1/libjava/java/lang/natStringBuffer.cc new file mode 100644 index 000000000..8fbb8dfbc --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natStringBuffer.cc @@ -0,0 +1,42 @@ +// natStringBuffer.cc - Implementation of java.lang.StringBuffer native methods. + +/* Copyright (C) 2001, 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <gcj/cni.h> +#include <java/lang/StringBuffer.h> + +java::lang::StringBuffer* +java::lang::StringBuffer::append (jint num) +{ + // Use an array large enough for "-2147483648"; i.e. 11 chars. + jchar buffer[11]; + int i = _Jv_FormatInt (buffer+11, num); + JvSynchronize dummy (this); + jint needed = count + i; + ensureCapacity_unsynchronized (needed); + jchar* dst = elements (value) + count; + jchar* src = buffer+11-i; + while (--i >= 0) + *dst++ = *src++; + count = needed; + return this; +} + +jboolean +java::lang::StringBuffer::regionMatches(jint toffset, jstring other) +{ + jint len = other->count; + jchar *tptr = elements(value) + toffset; + jchar *optr = JvGetStringChars(other); + while (--len >= 0) + if (*tptr++ != *optr++) + return false; + return true; +} diff --git a/gcc-4.2.1/libjava/java/lang/natStringBuilder.cc b/gcc-4.2.1/libjava/java/lang/natStringBuilder.cc new file mode 100644 index 000000000..e2c8c29f6 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natStringBuilder.cc @@ -0,0 +1,29 @@ +// Native methods for StringBuilder. + +/* Copyright (C) 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <gcj/cni.h> +#include <java/lang/StringBuilder.h> +#include <java/lang/String.h> + +jboolean +java::lang::StringBuilder::regionMatches(jint offset, jstring other) +{ + int len = other->count; + int index = 0; + jchar *sc = elements (value); + jchar *oc = _Jv_GetStringChars (other); + while (--len >= 0) + { + if (sc[offset++] != oc[index++]) + return false; + } + return true; +} diff --git a/gcc-4.2.1/libjava/java/lang/natSystem.cc b/gcc-4.2.1/libjava/java/lang/natSystem.cc new file mode 100644 index 000000000..42a13258d --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natSystem.cc @@ -0,0 +1,150 @@ +// natSystem.cc - Native code implementing System class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/System.h> +#include <java/lang/Class.h> +#include <java/lang/ArrayStoreException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/NullPointerException.h> +#include <java/io/PrintStream.h> +#include <java/io/InputStream.h> + + + +void +java::lang::System::setErr0 (java::io::PrintStream *newErr) +{ + err = newErr; +} + +void +java::lang::System::setIn0 (java::io::InputStream *newIn) +{ + in = newIn; +} + +void +java::lang::System::setOut0 (java::io::PrintStream *newOut) +{ + out = newOut; +} + +void +java::lang::System::arraycopy (jobject src, jint src_offset, + jobject dst, jint dst_offset, + jint count) +{ + if (! src || ! dst) + throw new NullPointerException; + + jclass src_c = src->getClass(); + jclass dst_c = dst->getClass(); + jclass src_comp = src_c->getComponentType(); + jclass dst_comp = dst_c->getComponentType(); + + if (! src_c->isArray() || ! dst_c->isArray() + || src_comp->isPrimitive() != dst_comp->isPrimitive() + || (src_comp->isPrimitive() && src_comp != dst_comp)) + throw new ArrayStoreException; + + __JArray *src_a = (__JArray *) src; + __JArray *dst_a = (__JArray *) dst; + if (src_offset < 0 || dst_offset < 0 || count < 0 + || (unsigned jint) src_offset > (unsigned jint) src_a->length + || (unsigned jint) (src_offset + count) > (unsigned jint) src_a->length + || (unsigned jint) dst_offset > (unsigned jint) dst_a->length + || (unsigned jint) (dst_offset + count) > (unsigned jint) dst_a->length) + throw new ArrayIndexOutOfBoundsException; + + // Do-nothing cases. + if ((src == dst && src_offset == dst_offset) + || ! count) + return; + + // If both are primitive, we can optimize trivially. If DST + // components are always assignable from SRC components, then we + // will never need to raise an error, and thus can do the + // optimization. If source and destinations are the same, then we + // know that the assignability premise always holds. + const bool prim = src_comp->isPrimitive(); + if (prim || dst_comp->isAssignableFrom(src_comp) || src == dst) + { + const size_t size = (prim ? src_comp->size() + : sizeof elements((jobjectArray)src)[0]); + + char *src_elts = _Jv_GetArrayElementFromElementType (src, src_comp); + src_elts += size * src_offset; + + char *dst_elts = _Jv_GetArrayElementFromElementType (dst, dst_comp); + dst_elts += size * dst_offset; + +#if HAVE_MEMMOVE + // We don't bother trying memcpy. It can't be worth the cost of + // the check. + // Don't cast to (void*), as memmove may expect (char*) + memmove (dst_elts, src_elts, count * size); +#else + bcopy (src_elts, dst_elts, count * size); +#endif + } + else + { + jobject *src_elts = elements ((jobjectArray) src_a) + src_offset; + jobject *dst_elts = elements ((jobjectArray) dst_a) + dst_offset; + + for (int i = 0; i < count; ++i) + { + if (*src_elts + && ! dst_comp->isAssignableFrom((*src_elts)->getClass())) + throw new ArrayStoreException; + *dst_elts++ = *src_elts++; + } + } +} + +jlong +java::lang::System::currentTimeMillis (void) +{ + return _Jv_platform_gettimeofday (); +} + +jlong +java::lang::System::nanoTime () +{ + return _Jv_platform_nanotime (); +} + +jint +java::lang::System::identityHashCode (jobject obj) +{ + return _Jv_HashCode (obj); +} + +jstring +java::lang::System::getenv0 (jstring name) +{ + jint len = _Jv_GetStringUTFLength (name); + char buf[len + 1]; + jsize total = JvGetStringUTFRegion (name, 0, name->length(), buf); + buf[total] = '\0'; + const char *value = ::getenv (buf); + if (value == NULL) + return NULL; + return JvNewStringUTF (value); +} diff --git a/gcc-4.2.1/libjava/java/lang/natThread.cc b/gcc-4.2.1/libjava/java/lang/natThread.cc new file mode 100644 index 000000000..facce30fa --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natThread.cc @@ -0,0 +1,472 @@ +// natThread.cc - Native part of Thread class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-threads.h> + +#include <gnu/gcj/RawDataManaged.h> +#include <java/lang/Thread.h> +#include <java/lang/ThreadGroup.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> + +#include <jni.h> + +#ifdef ENABLE_JVMPI +#include <jvmpi.h> +#endif + + + +// This structure is used to represent all the data the native side +// needs. An object of this type is assigned to the `data' member of +// the Thread class. +struct natThread +{ + // These are used to interrupt sleep and join calls. We can share a + // condition variable here since it only ever gets notified when the thread + // exits. + _Jv_Mutex_t join_mutex; + _Jv_ConditionVariable_t join_cond; + + // This is private data for the thread system layer. + _Jv_Thread_t *thread; + + // Each thread has its own JNI object. + JNIEnv *jni_env; +}; + +static void finalize_native (jobject ptr); + +// This is called from the constructor to initialize the native side +// of the Thread. +void +java::lang::Thread::initialize_native (void) +{ + natThread *nt = (natThread *) _Jv_AllocBytes (sizeof (natThread)); + + data = (gnu::gcj::RawDataManaged *) nt; + + // Register a finalizer to clean up the native thread resources. + _Jv_RegisterFinalizer (data, finalize_native); + + _Jv_MutexInit (&nt->join_mutex); + _Jv_CondInit (&nt->join_cond); + nt->thread = _Jv_ThreadInitData (this); + // FIXME: if JNI_ENV is set we will want to free it. It is + // malloc()d. + nt->jni_env = NULL; +} + +static void +finalize_native (jobject ptr) +{ + natThread *nt = (natThread *) ptr; + _Jv_ThreadDestroyData (nt->thread); +#ifdef _Jv_HaveCondDestroy + _Jv_CondDestroy (&nt->join_cond); +#endif +#ifdef _Jv_HaveMutexDestroy + _Jv_MutexDestroy (&nt->join_mutex); +#endif + _Jv_FreeJNIEnv(nt->jni_env); +} + +jint +java::lang::Thread::countStackFrames (void) +{ + // NOTE: This is deprecated in JDK 1.2. + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. + + return 0; +} + +java::lang::Thread * +java::lang::Thread::currentThread (void) +{ + return _Jv_ThreadCurrent (); +} + +jboolean +java::lang::Thread::holdsLock (jobject obj) +{ + if (!obj) + throw new NullPointerException; + return !_Jv_ObjectCheckMonitor (obj); +} + +void +java::lang::Thread::interrupt (void) +{ + checkAccess (); + natThread *nt = (natThread *) data; + JvSynchronize sync (this); + if (alive_flag) + _Jv_ThreadInterrupt (nt->thread); +} + +void +java::lang::Thread::join (jlong millis, jint nanos) +{ + if (millis < 0 || nanos < 0 || nanos > 999999) + throw new IllegalArgumentException; + + Thread *current = currentThread (); + + // Here `NT' is the native structure for the thread we are trying to join. + natThread *nt = (natThread *) data; + + // Now wait for: (1) an interrupt, (2) the thread to exit, or (3) + // the timeout to occur. + _Jv_MutexLock (&nt->join_mutex); + if (! isAlive ()) + { + _Jv_MutexUnlock (&nt->join_mutex); + return; + } + _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos); + _Jv_MutexUnlock (&nt->join_mutex); + + if (current->isInterrupted (true)) + throw new InterruptedException; +} + +void +java::lang::Thread::resume (void) +{ + checkAccess (); + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. +} + +void +java::lang::Thread::setPriority (jint newPriority) +{ + checkAccess (); + if (newPriority < MIN_PRIORITY || newPriority > MAX_PRIORITY) + throw new IllegalArgumentException; + + jint gmax = group->getMaxPriority(); + if (newPriority > gmax) + newPriority = gmax; + + priority = newPriority; + natThread *nt = (natThread *) data; + _Jv_ThreadSetPriority (nt->thread, priority); +} + +void +java::lang::Thread::sleep (jlong millis, jint nanos) +{ + if (millis < 0 || nanos < 0 || nanos > 999999) + throw new IllegalArgumentException; + + if (millis == 0 && nanos == 0) + ++nanos; + + Thread *current = currentThread (); + + // We use a condition variable to implement sleeping so that an + // interrupt can wake us up. + natThread *nt = (natThread *) current->data; + _Jv_MutexLock (&nt->join_mutex); + _Jv_CondWait (&nt->join_cond, &nt->join_mutex, millis, nanos); + _Jv_MutexUnlock (&nt->join_mutex); + + if (current->isInterrupted (true)) + throw new InterruptedException; +} + +void +java::lang::Thread::finish_ () +{ + natThread *nt = (natThread *) data; + + group->removeThread (this); + +#ifdef ENABLE_JVMPI + if (_Jv_JVMPI_Notify_THREAD_END) + { + JVMPI_Event event; + + event.event_type = JVMPI_EVENT_THREAD_END; + event.env_id = _Jv_GetCurrentJNIEnv (); + + _Jv_DisableGC (); + (*_Jv_JVMPI_Notify_THREAD_END) (&event); + _Jv_EnableGC (); + } +#endif + + // If a method cache was created, free it. + _Jv_FreeMethodCache(); + + // Clear out thread locals. + locals = NULL; + + // Signal any threads that are waiting to join() us. + _Jv_MutexLock (&nt->join_mutex); + + { + JvSynchronize sync (this); + alive_flag = false; + } + + _Jv_CondNotifyAll (&nt->join_cond, &nt->join_mutex); + _Jv_MutexUnlock (&nt->join_mutex); +} + +// Run once at thread startup, either when thread is attached or when +// _Jv_ThreadRun is called. +static void +_Jv_NotifyThreadStart (java::lang::Thread* thread) +{ +#ifdef ENABLE_JVMPI + if (_Jv_JVMPI_Notify_THREAD_START) + { + JVMPI_Event event; + + jstring thread_name = thread->getName (); + jstring group_name = NULL, parent_name = NULL; + java::lang::ThreadGroup *group = thread->getThreadGroup (); + + if (group) + { + group_name = group->getName (); + group = group->getParent (); + + if (group) + parent_name = group->getName (); + } + + int thread_len = thread_name ? JvGetStringUTFLength (thread_name) : 0; + int group_len = group_name ? JvGetStringUTFLength (group_name) : 0; + int parent_len = parent_name ? JvGetStringUTFLength (parent_name) : 0; + + char thread_chars[thread_len + 1]; + char group_chars[group_len + 1]; + char parent_chars[parent_len + 1]; + + if (thread_name) + JvGetStringUTFRegion (thread_name, 0, + thread_name->length(), thread_chars); + if (group_name) + JvGetStringUTFRegion (group_name, 0, + group_name->length(), group_chars); + if (parent_name) + JvGetStringUTFRegion (parent_name, 0, + parent_name->length(), parent_chars); + + thread_chars[thread_len] = '\0'; + group_chars[group_len] = '\0'; + parent_chars[parent_len] = '\0'; + + event.event_type = JVMPI_EVENT_THREAD_START; + event.env_id = NULL; + event.u.thread_start.thread_name = thread_chars; + event.u.thread_start.group_name = group_chars; + event.u.thread_start.parent_name = parent_chars; + event.u.thread_start.thread_id = (jobjectID) thread; + event.u.thread_start.thread_env_id = _Jv_GetCurrentJNIEnv (); + + _Jv_DisableGC (); + (*_Jv_JVMPI_Notify_THREAD_START) (&event); + _Jv_EnableGC (); + } +#endif +} + +void +_Jv_ThreadRun (java::lang::Thread* thread) +{ + try + { + _Jv_NotifyThreadStart (thread); + thread->run (); + } + catch (java::lang::Throwable *t) + { + // Uncaught exceptions are forwarded to the ThreadGroup. If + // this results in an uncaught exception, that is ignored. + try + { + thread->group->uncaughtException (thread, t); + } + catch (java::lang::Throwable *f) + { + // Nothing. + } + } + + thread->finish_ (); +} + +_Jv_Thread_t* +_Jv_ThreadGetData (java::lang::Thread* thread) +{ + natThread* nt = (natThread*) thread->data; + return nt->thread; +} + +void +java::lang::Thread::start (void) +{ + JvSynchronize sync (this); + + // Its illegal to re-start() a thread, even if its dead. + if (!startable_flag) + throw new IllegalThreadStateException; + + alive_flag = true; + startable_flag = false; + natThread *nt = (natThread *) data; + _Jv_ThreadStart (this, nt->thread, (_Jv_ThreadStartFunc *) &_Jv_ThreadRun); +} + +void +java::lang::Thread::stop (java::lang::Throwable *) +{ + checkAccess (); + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. +} + +void +java::lang::Thread::suspend (void) +{ + checkAccess (); + + // Old applets still call this method. Rather than throwing + // UnsupportedOperationException we simply fail silently. +} + +static int nextThreadNumber = 0; + +jstring +java::lang::Thread::gen_name (void) +{ + jint i; + jclass sync = &java::lang::Thread::class$; + { + JvSynchronize dummy(sync); + i = ++nextThreadNumber; + } + + // Use an array large enough for "-2147483648"; i.e. 11 chars, + "Thread-". + jchar buffer[7+11]; + jchar *bufend = (jchar *) ((char *) buffer + sizeof(buffer)); + i = _Jv_FormatInt (bufend, i); + jchar *ptr = bufend - i; + // Prepend "Thread-". + *--ptr = '-'; + *--ptr = 'd'; + *--ptr = 'a'; + *--ptr = 'e'; + *--ptr = 'r'; + *--ptr = 'h'; + *--ptr = 'T'; + return JvNewString (ptr, bufend - ptr); +} + +void +java::lang::Thread::yield (void) +{ + _Jv_ThreadYield (); +} + +JNIEnv * +_Jv_GetCurrentJNIEnv () +{ + java::lang::Thread *t = _Jv_ThreadCurrent (); + if (t == NULL) + return NULL; + return ((natThread *) t->data)->jni_env; +} + +void +_Jv_SetCurrentJNIEnv (JNIEnv *env) +{ + java::lang::Thread *t = _Jv_ThreadCurrent (); + JvAssert (t != NULL); + ((natThread *) t->data)->jni_env = env; +} + +// Attach the current native thread to an existing (but unstarted) Thread +// object. Does not register thread with the garbage collector. +// Returns -1 on failure, 0 upon success. +jint +_Jv_AttachCurrentThread(java::lang::Thread* thread) +{ + JvSynchronize sync (thread); + if (thread == NULL || thread->startable_flag == false) + return -1; + thread->startable_flag = false; + thread->alive_flag = true; + natThread *nt = (natThread *) thread->data; + _Jv_ThreadRegister (nt->thread); + return 0; +} + +java::lang::Thread* +_Jv_AttachCurrentThread(jstring name, java::lang::ThreadGroup* group) +{ + // Register thread with GC before attempting any allocations. + _Jv_GCAttachThread (); + java::lang::Thread *thread = _Jv_ThreadCurrent (); + if (thread != NULL) + return thread; + if (name == NULL) + name = java::lang::Thread::gen_name (); + thread = new java::lang::Thread (NULL, group, NULL, name); + _Jv_AttachCurrentThread (thread); + _Jv_NotifyThreadStart (thread); + return thread; +} + +java::lang::Thread* +_Jv_AttachCurrentThreadAsDaemon(jstring name, java::lang::ThreadGroup* group) +{ + java::lang::Thread *thread = _Jv_ThreadCurrent (); + if (thread != NULL) + return thread; + if (name == NULL) + name = java::lang::Thread::gen_name (); + thread = new java::lang::Thread (NULL, group, NULL, name); + thread->setDaemon (true); + _Jv_AttachCurrentThread (thread); + _Jv_NotifyThreadStart (thread); + return thread; +} + +jint +_Jv_DetachCurrentThread (void) +{ + java::lang::Thread *t = _Jv_ThreadCurrent (); + if (t == NULL) + return -1; + + _Jv_ThreadUnRegister (); + _Jv_GCDetachThread (); + // Release the monitors. + t->finish_ (); + + return 0; +} diff --git a/gcc-4.2.1/libjava/java/lang/natVMClassLoader.cc b/gcc-4.2.1/libjava/java/lang/natVMClassLoader.cc new file mode 100644 index 000000000..95c1f1593 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natVMClassLoader.cc @@ -0,0 +1,230 @@ +// natVMClassLoader.cc - VMClassLoader native methods + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +/* Author: Kresten Krab Thorup <krab@gnu.org> */ + +#include <config.h> + +#include <stdlib.h> +#include <string.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java-threads.h> +#include <java-interp.h> + +#include <java/lang/VMClassLoader.h> +#include <java/lang/VMCompiler.h> +#include <gnu/gcj/runtime/ExtensionClassLoader.h> +#include <gnu/gcj/runtime/SystemClassLoader.h> +#include <gnu/gcj/runtime/BootClassLoader.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/Class.h> +#include <java/lang/Throwable.h> +#include <java/security/ProtectionDomain.h> +#include <java/lang/ClassFormatError.h> +#include <java/lang/StringBuffer.h> +#include <java/lang/Runtime.h> +#include <java/util/HashSet.h> +#include <java/lang/VirtualMachineError.h> + +java::lang::Class * +java::lang::VMClassLoader::defineClass (java::lang::ClassLoader *loader, + jstring name, + jbyteArray data, + jint offset, + jint length, + java::security::ProtectionDomain *pd) +{ + jclass klass = VMCompiler::compileClass(loader, name, data, + offset, length, pd); + +#ifdef INTERPRETER + if (klass == NULL) + { + klass = new java::lang::Class (); + + // Synchronize on the class, so that it is not attempted initialized + // until we're done loading. + JvSynchronize sync (klass); + + // Record the defining loader. For the bootstrap class loader, + // we record NULL. + if (loader != bootLoader) + klass->loader = loader; + + if (name != 0) + { + _Jv_Utf8Const *name2 = _Jv_makeUtf8Const (name); + + if (! _Jv_VerifyClassName (name2)) + throw new java::lang::ClassFormatError + (JvNewStringLatin1 ("erroneous class name")); + + klass->name = name2; + } + + _Jv_Utf8Const *found_name = NULL; + try + { + _Jv_DefineClass (klass, data, offset, length, pd, &found_name); + } + catch (java::lang::Throwable *ex) + { + klass->state = JV_STATE_ERROR; + klass->notifyAll (); + + if (found_name != NULL) + _Jv_UnregisterInitiatingLoader (klass, klass->loader); + + // If EX is not a ClassNotFoundException, that's ok, because we + // account for the possibility in defineClass(). + throw ex; + } + + // if everything proceeded sucessfully, we're loaded. + JvAssert (klass->state == JV_STATE_LOADED); + } +#endif // INTERPRETER + + if (! klass) + { + StringBuffer *sb = new StringBuffer(); + if (name) + { + sb->append(JvNewStringLatin1("found class file for class ")); + sb->append(name); + } + else + sb->append(JvNewStringLatin1("found unnamed class file")); + sb->append(JvNewStringLatin1(", but no interpreter configured in this libgcj")); + throw new VirtualMachineError(sb->toString()); + } + + return klass; +} + +java::lang::ClassLoader * +java::lang::VMClassLoader::getSystemClassLoaderInternal() +{ + _Jv_InitClass (&gnu::gcj::runtime::ExtensionClassLoader::class$); + _Jv_CopyClassesToSystemLoader (gnu::gcj::runtime::ExtensionClassLoader::system_instance); + return gnu::gcj::runtime::ExtensionClassLoader::system_instance; +} + +jclass +java::lang::VMClassLoader::getPrimitiveClass (jchar type) +{ + char sig[2]; + sig[0] = (char) type; + sig[1] = '\0'; + // Note: this cannot return NULL, since the input is always correct. + return _Jv_FindClassFromSignature (sig, NULL); +} + +void +java::lang::VMClassLoader::initBootLoader(jstring libdir) +{ + bootLoader = new gnu::gcj::runtime::BootClassLoader(libdir); +} + +jclass +java::lang::VMClassLoader::nativeFindClass (jstring name) +{ + jclass klass = NULL; + + if (lib_control != LIB_NEVER) + { + // Turn `gnu.pkg.quux' into `lib-gnu-pkg-quux'. Then search for + // a module named (eg, on Linux) `lib-gnu-pkg-quux.so', followed + // by `lib-gnu-pkg.so' and `lib-gnu.so'. If loading one of + // these causes the class to appear in the cache, then use it. + java::lang::StringBuffer *sb + = new java::lang::StringBuffer (JvNewStringLatin1("lib-")); + // Skip inner classes + jstring cn; + jint ci = name->indexOf('$'); + if (ci == -1) + cn = name; + else + cn = name->substring (0, ci); + jstring so_base_name + = (sb->append (cn)->toString ())->replace ('.', '-'); + + using namespace ::java::lang; + Runtime *rt = Runtime::getRuntime(); + + _Jv_Utf8Const *name_u = NULL; + + // Compare against `3' because that is the length of "lib". + while (! klass && so_base_name && so_base_name->length() > 3) + { + if (lib_control == LIB_CACHE) + { + // If we've already tried this name, we're done. + if (tried_libraries->contains(so_base_name)) + break; + tried_libraries->add(so_base_name); + } + + jboolean loaded = rt->loadLibraryInternal (so_base_name); + + jint nd = so_base_name->lastIndexOf ('-'); + if (nd == -1) + so_base_name = NULL; + else + so_base_name = so_base_name->substring (0, nd); + + if (loaded) + { + if (name_u == NULL) + name_u = _Jv_makeUtf8Const (name); + klass = _Jv_FindClassInCache (name_u); + } + } + } + + if (klass) + definePackageForNative(name); + + return klass; +} + +jclass +java::lang::VMClassLoader::loadClass(jstring name, jboolean resolve) +{ + // We try the boot loader first, so that the endorsed directory + // overrides compiled-in classes. + jclass klass = NULL; + if (bootLoader) + klass = bootLoader->bootLoadClass(name); + if (! klass) + { + _Jv_Utf8Const *utf = _Jv_makeUtf8Const (name); + klass = _Jv_FindClassInCache (utf); + } + if (! klass) + klass = nativeFindClass(name); + if (klass) + { + // We never want to return a class without its supers linked. + // It isn't clear from the spec, but this is what other + // implementations do in practice. + if (resolve) + resolveClass (klass); + else + _Jv_Linker::wait_for_state (klass, JV_STATE_LOADING); + + definePackageForNative(name); + } + + return klass; +} diff --git a/gcc-4.2.1/libjava/java/lang/natVMSecurityManager.cc b/gcc-4.2.1/libjava/java/lang/natVMSecurityManager.cc new file mode 100644 index 000000000..9d52c92c7 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natVMSecurityManager.cc @@ -0,0 +1,29 @@ +/* Copyright (C) 2002 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@redhat.com> + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/lang/VMSecurityManager.h> +#include <java/lang/SecurityManager.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/Class.h> + +JArray<jclass> * +java::lang::VMSecurityManager::getClassContext (jclass klass) +{ + JArray<jclass> *result = + _Jv_StackTrace::GetClassContext (klass); + + return result; +} diff --git a/gcc-4.2.1/libjava/java/lang/natVMThrowable.cc b/gcc-4.2.1/libjava/java/lang/natVMThrowable.cc new file mode 100644 index 000000000..b198f9073 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natVMThrowable.cc @@ -0,0 +1,45 @@ +// natVMThrowable.cc - Native part of VMThrowable class. + +/* Copyright (C) 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/lang/Throwable.h> +#include <java/lang/VMThrowable.h> + +using namespace gnu::gcj; + +java::lang::VMThrowable * +java::lang::VMThrowable::fillInStackTrace (java::lang::Throwable *) +{ + using namespace java::lang; + + // Don't trace stack during initialization of the runtime. + if (! gcj::runtimeInitialized) + return NULL; + + _Jv_StackTrace *trace = _Jv_StackTrace::GetStackTrace (); + VMThrowable *vmthrowable = new VMThrowable (); + vmthrowable->data = (RawDataManaged *) trace; + return vmthrowable; +} + + +JArray< ::java::lang::StackTraceElement *> * +java::lang::VMThrowable::getStackTrace (java::lang::Throwable *throwable) +{ + _Jv_StackTrace *trace = reinterpret_cast <_Jv_StackTrace *> (data); + return _Jv_StackTrace::GetStackTraceElements (trace, throwable); +} diff --git a/gcc-4.2.1/libjava/java/lang/natWin32Process.cc b/gcc-4.2.1/libjava/java/lang/natWin32Process.cc new file mode 100644 index 000000000..1ac3a2abd --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/natWin32Process.cc @@ -0,0 +1,351 @@ +// natWin32Process.cc - Native side of Win32 process code. + +/* Copyright (C) 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +// Conflicts with the definition in "java/lang/reflect/Modifier.h" +#undef STRICT + +#include <java/lang/ConcreteProcess.h> +#include <java/lang/IllegalThreadStateException.h> +#include <java/lang/InterruptedException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Thread.h> +#include <java/io/File.h> +#include <java/io/FileDescriptor.h> +#include <java/io/FileInputStream.h> +#include <java/io/FileOutputStream.h> +#include <java/io/IOException.h> +#include <java/lang/OutOfMemoryError.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> + +using gnu::java::nio::channels::FileChannelImpl; + +void +java::lang::ConcreteProcess::cleanup (void) +{ + // FIXME: + // We used to close the input, output and + // error streams here, but we can't do that + // because the caller also has the right + // to close these and FileInputStream and FileOutputStream + // scream if you attempt to close() them twice. Presently, + // we use _Jv_platform_close_on_exec, which is similar + // to the POSIX approach. + // + // What I wanted to do is have private nested + // classes in ConcreteProcess which extend FileInputStream + // and FileOutputStream, respectively, but override + // close() to permit multiple calls to close(). This + // led to class header and platform configury issues + // that I didn't feel like dealing with. However, + // this approach could conceivably be a good multiplatform + // one since delaying the pipe close until process + // termination could be wasteful if many child processes + // are spawned within the parent process' lifetime. + inputStream = NULL; + outputStream = NULL; + errorStream = NULL; + + if (procHandle) + { + CloseHandle((HANDLE) procHandle); + procHandle = (jint) INVALID_HANDLE_VALUE; + } +} + +void +java::lang::ConcreteProcess::destroy (void) +{ + if (! hasExited ()) + { + // Kill it forcibly and assign an (arbitrary) exit code of 0. + TerminateProcess ((HANDLE) procHandle, 0); + exitCode = 0; + + cleanup (); + } +} + +jboolean +java::lang::ConcreteProcess::hasExited (void) +{ + DWORD exitStatus; + + if (GetExitCodeProcess ((HANDLE) procHandle, &exitStatus) != 0) + { + // NOTE: STILL_ACTIVE is defined as "259" by Win32 - if the + // child actually exits with this return code, we have a + // problem here. See MSDN documentation on GetExitCodeProcess( ). + + if (exitStatus == STILL_ACTIVE) + return false; + else + { + cleanup (); + exitCode = exitStatus; + return true; + } + } + else + return true; +} + +jint +java::lang::ConcreteProcess::waitFor (void) +{ + if (! hasExited ()) + { + DWORD exitStatus = 0UL; + + // Set up our waitable objects array + // - 0: the handle to the process we just launched + // - 1: our thread's interrupt event + HANDLE arh[2]; + arh[0] = (HANDLE) procHandle; + arh[1] = _Jv_Win32GetInterruptEvent (); + DWORD rval = WaitForMultipleObjects (2, arh, 0, INFINITE); + + // Use the returned value from WaitForMultipleObjects + // instead of our thread's interrupt_flag to test for + // thread interruption. See the comment for + // _Jv_Win32GetInterruptEvent(). + bool bInterrupted = rval == (WAIT_OBJECT_0 + 1); + + if (bInterrupted) + { + // Querying this forces a reset our thread's interrupt flag. + Thread::interrupted(); + + cleanup (); + throw new InterruptedException (); + } + + GetExitCodeProcess ((HANDLE) procHandle, &exitStatus); + exitCode = exitStatus; + + cleanup (); + } + + return exitCode; +} + + +// Helper class for creating and managing the pipes +// used for I/O redirection for child processes. +class ChildProcessPipe +{ +public: + // Indicates from the child process' point of view + // whether the pipe is for reading or writing. + enum EType {INPUT, OUTPUT}; + + ChildProcessPipe(EType eType); + ~ChildProcessPipe(); + + // Returns a pipe handle suitable for use by the parent process + HANDLE getParentHandle(); + + // Returns a pipe handle suitable for use by the child process. + HANDLE getChildHandle(); + +private: + EType m_eType; + HANDLE m_hRead, m_hWrite; +}; + +ChildProcessPipe::ChildProcessPipe(EType eType): + m_eType(eType) +{ + SECURITY_ATTRIBUTES sAttrs; + + // Explicitly allow the handles to the pipes to be inherited. + sAttrs.nLength = sizeof (SECURITY_ATTRIBUTES); + sAttrs.bInheritHandle = 1; + sAttrs.lpSecurityDescriptor = NULL; + + if (CreatePipe (&m_hRead, &m_hWrite, &sAttrs, 0) == 0) + { + DWORD dwErrorCode = GetLastError (); + throw new java::io::IOException ( + _Jv_WinStrError (_T("Error creating pipe"), dwErrorCode)); + } + + // If this is the read end of the child, we need + // to make the parent write end non-inheritable. Similarly, + // if this is the write end of the child, we need to make + // the parent read end non-inheritable. If we didn't + // do this, the child would inherit these ends and we wouldn't + // be able to close them from our end. For full details, + // do a Google search on "Q190351". + HANDLE& rhStd = m_eType==INPUT ? m_hWrite : m_hRead; + _Jv_platform_close_on_exec (rhStd); +} + +ChildProcessPipe::~ChildProcessPipe() +{ + // Close the parent end of the pipe. This + // destructor is called after the child process + // has been spawned. + CloseHandle(getChildHandle()); +} + +HANDLE ChildProcessPipe::getParentHandle() +{ + return m_eType==INPUT ? m_hWrite : m_hRead; +} + +HANDLE ChildProcessPipe::getChildHandle() +{ + return m_eType==INPUT ? m_hRead : m_hWrite; +} + +void +java::lang::ConcreteProcess::startProcess (jstringArray progarray, + jstringArray envp, + java::io::File *dir) +{ + using namespace java::io; + + procHandle = (jint) INVALID_HANDLE_VALUE; + + // Reconstruct the command line. + jstring *elts = elements (progarray); + + int cmdLineLen = 0; + + for (int i = 0; i < progarray->length; ++i) + cmdLineLen += (elts[i]->length() + 1); + + LPTSTR cmdLine = (LPTSTR) _Jv_Malloc ((cmdLineLen + 1) * sizeof(TCHAR)); + LPTSTR cmdLineCurPos = cmdLine; + + for (int i = 0; i < progarray->length; ++i) + { + if (i > 0) + *cmdLineCurPos++ = _T(' '); + + jint len = elts[i]->length(); + JV_TEMP_STRING_WIN32(thiselt, elts[i]); + _tcscpy(cmdLineCurPos, thiselt); + cmdLineCurPos += len; + } + *cmdLineCurPos = _T('\0'); + + // Get the environment, if any. Unconditionally + // create a UNICODE environment, even on ANSI + // builds. + LPWSTR env = NULL; + if (envp) + { + elts = elements (envp); + + int envLen = 0; + for (int i = 0; i < envp->length; ++i) + envLen += (elts[i]->length() + 1); + + env = (LPWSTR) _Jv_Malloc ((envLen + 1) * sizeof(WCHAR)); + + int j = 0; + for (int i = 0; i < envp->length; ++i) + { + jstring elt = elts[i]; + jint len = elt->length(); + + wcsncpy(env + j, (LPCWSTR) JvGetStringChars(elt), len); + + j += len; + + // Insert the null terminator and skip past it. + env[j++] = 0; + } + *(env + j) = 0; + } + + // Get the working directory path, if specified. + JV_TEMP_STRING_WIN32 (wdir, dir ? dir->getPath () : 0); + + errorStream = NULL; + inputStream = NULL; + outputStream = NULL; + + java::lang::Throwable *exc = NULL; + + try + { + // We create anonymous pipes to communicate with the child + // on each of standard streams. + ChildProcessPipe aChildStdIn(ChildProcessPipe::INPUT); + ChildProcessPipe aChildStdOut(ChildProcessPipe::OUTPUT); + ChildProcessPipe aChildStdErr(ChildProcessPipe::OUTPUT); + + outputStream = new FileOutputStream (new FileChannelImpl ( + (jint) aChildStdIn.getParentHandle (), + FileChannelImpl::WRITE)); + inputStream = new FileInputStream (new FileChannelImpl ( + (jint) aChildStdOut.getParentHandle (), + FileChannelImpl::READ)); + errorStream = new FileInputStream (new FileChannelImpl ( + (jint) aChildStdErr.getParentHandle (), + FileChannelImpl::READ)); + + // Now create the child process. + PROCESS_INFORMATION pi; + STARTUPINFO si; + + ZeroMemory (&pi, sizeof (PROCESS_INFORMATION)); + + ZeroMemory (&si, sizeof (STARTUPINFO)); + si.cb = sizeof (STARTUPINFO); + + // Explicitly specify the handles to the standard streams. + si.dwFlags |= STARTF_USESTDHANDLES; + + si.hStdInput = aChildStdIn.getChildHandle(); + si.hStdOutput = aChildStdOut.getChildHandle(); + si.hStdError = aChildStdErr.getChildHandle(); + + // Spawn the process. CREATE_NO_WINDOW only applies when + // starting a console application; it suppresses the + // creation of a console window. This flag is ignored on + // Win9X. + + if (CreateProcess (NULL, + cmdLine, + NULL, + NULL, + 1, + CREATE_NO_WINDOW | CREATE_UNICODE_ENVIRONMENT, + env, + wdir, + &si, + &pi) == 0) + { + DWORD dwErrorCode = GetLastError (); + throw new IOException ( + _Jv_WinStrError (_T("Error creating child process"), dwErrorCode)); + } + + procHandle = (jint ) pi.hProcess; + + _Jv_Free (cmdLine); + if (env != NULL) + _Jv_Free (env); + } + catch (java::lang::Throwable *thrown) + { + cleanup (); + exc = thrown; + } + + if (exc != NULL) + throw exc; +} diff --git a/gcc-4.2.1/libjava/java/lang/ref/Reference.java b/gcc-4.2.1/libjava/java/lang/ref/Reference.java new file mode 100644 index 000000000..ab0c55c84 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/ref/Reference.java @@ -0,0 +1,210 @@ +/* java.lang.ref.Reference + Copyright (C) 1999, 2002, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.ref; + +/** + * This is the base class of all references. A reference allows + * refering to an object without preventing the garbage collector to + * collect it. The only way to get the referred object is via the + * <code>get()</code>-method. This method will return + * <code>null</code> if the object was collected. <br> + * + * A reference may be registered with a queue. When a referred + * element gets collected the reference will be put on the queue, so + * that you will be notified. <br> + * + * There are currently three types of references: soft reference, + * weak reference and phantom reference. <br> + * + * Soft references will be cleared if the garbage collector is told + * to free some memory and there are no unreferenced or weakly referenced + * objects. It is useful for caches. <br> + * + * Weak references will be cleared as soon as the garbage collector + * determines that the refered object is only weakly reachable. They + * are useful as keys in hashtables (see <code>WeakHashtable</code>) as + * you get notified when nobody has the key anymore. + * + * Phantom references don't prevent finalization. If an object is only + * phantom reachable, it will be finalized, and the reference will be + * enqueued, but not cleared. Since you mustn't access an finalized + * object, the <code>get</code> method of a phantom reference will never + * work. It is useful to keep track, when an object is finalized. + * + * @author Jochen Hoenicke + * @see java.util.WeakHashtable + */ +public abstract class Reference +{ + /** + * The underlying object. This field is handled in a special way by + * the garbage collector. + * GCJ LOCAL: + * This is a RawData because it must be disguised from the GC. + * END GCJ LOCAL + */ + gnu.gcj.RawData referent; + + /** + * This is like REFERENT but is not scanned by the GC. We keep a + * copy around so that we can clean up our internal data structure + * even after clear() is called. + * GCJ LOCAL: + * This field doesn't exist in Classpath. + * END GCJ LOCAL + */ + gnu.gcj.RawData copy; + + /** + * Set to true if {@link #clear()} is called. + * GCJ LOCAL: + * This field doesn't exist in Classpath. It is used internally in + * natReference.cc, which enqueues the reference unless it is true + * (has been cleared). + * END GCJ LOCAL + */ + boolean cleared = false; + + /** + * The queue this reference is registered on. This is null, if this + * wasn't registered to any queue or reference was already enqueued. + */ + ReferenceQueue queue; + + /** + * Link to the next entry on the queue. If this is null, this + * reference is not enqueued. Otherwise it points to the next + * reference. The last reference on a queue will point to itself + * (not to null, that value is used to mark a not enqueued + * reference). + */ + Reference nextOnQueue; + + /** + * This lock should be taken by the garbage collector, before + * determining reachability. It will prevent the get()-method to + * return the reference so that reachability doesn't change. + */ + static Object lock = new Object(); + + /** + * Creates a new reference that is not registered to any queue. + * Since it is package private, it is not possible to overload this + * class in a different package. + * @param referent the object we refer to. + */ + Reference(Object ref) + { + create (ref); + } + + /** + * Creates a reference that is registered to a queue. Since this is + * package private, it is not possible to overload this class in a + * different package. + * @param referent the object we refer to. + * @param q the reference queue to register on. + * @exception NullPointerException if q is null. + */ + Reference(Object ref, ReferenceQueue q) + { + if (q == null) + throw new NullPointerException(); + queue = q; + create (ref); + } + + /** + * Notifies the VM that a new Reference has been created. + */ + private native void create (Object o); + + /** + * Returns the object, this reference refers to. + * @return the object, this reference refers to, or null if the + * reference was cleared. + */ + public Object get() + { + synchronized (lock) + { + return referent; + } + } + + /** + * Clears the reference, so that it doesn't refer to its object + * anymore. For soft and weak references this is called by the + * garbage collector. For phantom references you should call + * this when enqueuing the reference. + */ + public void clear() + { + // Must synchronize so changes are visible in finalizer thread. + synchronized (lock) + { + referent = null; + cleared = true; + } + } + + /** + * Tells if the object is enqueued on a reference queue. + * @return true if it is enqueued, false otherwise. + */ + public boolean isEnqueued() + { + return nextOnQueue != null; + } + + /** + * Enqueue an object on a reference queue. This is normally executed + * by the garbage collector. + */ + public boolean enqueue() + { + if (queue != null && nextOnQueue == null) + { + queue.enqueue(this); + queue = null; + return true; + } + return false; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/ref/natReference.cc b/gcc-4.2.1/libjava/java/lang/ref/natReference.cc new file mode 100644 index 000000000..23f435f4d --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/ref/natReference.cc @@ -0,0 +1,370 @@ +// natReference.cc - Native code for References + +/* Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@redhat.com> + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/lang/Throwable.h> +#include <java/lang/ref/Reference.h> +#include <java/lang/ref/SoftReference.h> +#include <java/lang/ref/WeakReference.h> +#include <java/lang/ref/PhantomReference.h> +#include <java/lang/ref/ReferenceQueue.h> + +static void finalize_reference (jobject ref); +static void finalize_referred_to_object (jobject obj); + + + +enum weight +{ + SOFT = 0, + WEAK = 1, + FINALIZE = 2, + PHANTOM = 3, + + // This is used to mark the head of a list. + HEAD = 4, + + // This is used to mark a deleted item. + DELETED = 5 +}; + +// Objects of this type are used in the hash table to keep track of +// the mapping between a finalizable object and the various References +// which refer to it. +struct object_list +{ + // The reference object. This is NULL for FINALIZE weight. + jobject reference; + + // The weight of this object. + enum weight weight; + + // Next in list. + object_list *next; +}; + +// Hash table used to hold mapping from object to References. The +// object_list item in the hash holds the object itself in the +// reference field; chained to it are all the references sorted in +// order of weight (lowest first). +static object_list *hash = NULL; + +// Number of slots used in HASH. +static int hash_count = 0; + +// Number of slots total in HASH. Must be power of 2. +static int hash_size = 0; + +#define DELETED_REFERENCE ((jobject) -1) + +static object_list * +find_slot (jobject key) +{ + jint hcode = _Jv_HashCode (key); + /* step must be non-zero, and relatively prime with hash_size. */ + jint step = (hcode ^ (hcode >> 16)) | 1; + int start_index = hcode & (hash_size - 1); + int index = start_index; + int deleted_index = -1; + do + { + object_list *ptr = &hash[index]; + if (ptr->reference == key) + return ptr; + else if (ptr->reference == NULL) + { + if (deleted_index == -1) + return ptr; + else + return &hash[deleted_index]; + } + else if (ptr->weight == DELETED) + { + deleted_index = index; + JvAssert (ptr->reference == DELETED_REFERENCE); + } + index = (index + step) & (hash_size - 1); + } + while (index != start_index); + // Note that we can have INDEX == START_INDEX if the table has no + // NULL entries but does have DELETED entries. + JvAssert (deleted_index >= 0); + return &hash[deleted_index]; +} + +static void +rehash () +{ + if (hash == NULL) + { + hash_size = 1024; + hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list)); + memset (hash, 0, hash_size * sizeof (object_list)); + } + else + { + object_list *old = hash; + int i = hash_size; + + hash_size *= 2; + hash = (object_list *) _Jv_Malloc (hash_size * sizeof (object_list)); + memset (hash, 0, hash_size * sizeof (object_list)); + + while (--i >= 0) + { + if (old[i].reference == NULL || old[i].weight == DELETED) + continue; + object_list *newslot = find_slot (old[i].reference); + *newslot = old[i]; + } + + _Jv_Free (old); + } +} + +// Remove a Reference. +static void +remove_from_hash (jobject obj) +{ + java::lang::ref::Reference *ref + = reinterpret_cast<java::lang::ref::Reference *> (obj); + object_list *head = find_slot (ref->copy); + + // We might have found a new slot. We can just ignore that here. + if (head->reference != ref->copy) + return; + + object_list **link = &head->next; + head = head->next; + + while (head && head->reference != ref) + { + link = &head->next; + head = head->next; + } + + // Remove the slot. + if (head) + { + *link = head->next; + _Jv_Free (head); + } +} + +// Return list head if object is in hash, NULL otherwise. +object_list * +in_hash (jobject obj) +{ + // The hash table might not yet be initialized. + if (hash == NULL) + return NULL; + object_list *head = find_slot (obj); + if (head->reference != obj) + return NULL; + return head; +} + +// FIXME what happens if an object's finalizer creates a Reference to +// the object, and the object has never before been added to the hash? +// Madness! + +// Add an item to the hash table. If the item is new, we also add a +// finalizer item. We keep items in the hash table until they are +// completely collected; this lets us know when an item is new, even +// if it has been resurrected after its finalizer has been run. +static void +add_to_hash (java::lang::ref::Reference *the_reference) +{ + JvSynchronize sync (java::lang::ref::Reference::lock); + + if (3 * hash_count >= 2 * hash_size) + rehash (); + + // Use `copy' here because the `referent' field has been cleared. + jobject referent = the_reference->copy; + object_list *item = find_slot (referent); + if (item->reference == NULL || item->reference == DELETED_REFERENCE) + { + // New item, so make an entry for the finalizer. + item->reference = referent; + item->weight = HEAD; + + item->next = (object_list *) _Jv_Malloc (sizeof (object_list)); + item->next->reference = NULL; + item->next->weight = FINALIZE; + item->next->next = NULL; + ++hash_count; + } + + object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list)); + n->reference = the_reference; + + enum weight w = PHANTOM; + if (java::lang::ref::SoftReference::class$.isInstance (the_reference)) + w = SOFT; + else if (java::lang::ref::WeakReference::class$.isInstance (the_reference)) + w = WEAK; + n->weight = w; + + object_list **link = &item->next; + object_list *iter = *link; + while (iter && iter->weight < n->weight) + { + link = &iter->next; + iter = *link; + } + n->next = *link; + *link = n; +} + +// Add a FINALIZE entry if one doesn't exist. +static void +maybe_add_finalize (object_list *entry, jobject obj) +{ + object_list **link = &entry->next; + object_list *iter = *link; + while (iter && iter->weight < FINALIZE) + { + link = &iter->next; + iter = *link; + } + + // We want at most one FINALIZE entry in the queue. + if (iter && iter->weight == FINALIZE) + return; + + object_list *n = (object_list *) _Jv_Malloc (sizeof (object_list)); + n->reference = obj; + n->weight = FINALIZE; + n->next = *link; + *link = n; +} + +// This is called when an object is ready to be finalized. This +// actually implements the appropriate Reference semantics. +static void +finalize_referred_to_object (jobject obj) +{ + JvSynchronize sync (java::lang::ref::Reference::lock); + + object_list *list = find_slot (obj); + object_list *head = list->next; + if (head == NULL) + { + // We have a truly dead object: the object's finalizer has been + // run, all the object's references have been processed, and the + // object is unreachable. There is, at long last, no way to + // resurrect it. + list->reference = DELETED_REFERENCE; + list->weight = DELETED; + --hash_count; + return; + } + + enum weight w = head->weight; + if (w == FINALIZE) + { + // Update the list first, as _Jv_FinalizeString might end up + // looking at this data structure. + list->next = head->next; + _Jv_Free (head); + + // If we have a Reference A to a Reference B, and B is + // finalized, then we have to take special care to make sure + // that B is properly deregistered. This is super gross. FIXME + // will it fail if B's finalizer resurrects B? + if (java::lang::ref::Reference::class$.isInstance (obj)) + finalize_reference (obj); + else if (obj->getClass() == &java::lang::String::class$) + _Jv_FinalizeString (obj); + else + _Jv_FinalizeObject (obj); + } + else if (w != SOFT || _Jv_GCCanReclaimSoftReference (obj)) + { + // If we just decided to reclaim a soft reference, we might as + // well do all the weak references at the same time. + if (w == SOFT) + w = WEAK; + + while (head && head->weight <= w) + { + java::lang::ref::Reference *ref + = reinterpret_cast<java::lang::ref::Reference *> (head->reference); + if (! ref->cleared) + ref->enqueue (); + + object_list *next = head->next; + _Jv_Free (head); + head = next; + } + list->next = head; + } + + // Re-register this finalizer. We always re-register because we + // can't know until the next collection cycle whether or not the + // object is truly unreachable. + _Jv_RegisterFinalizer (obj, finalize_referred_to_object); +} + +// This is called when a Reference object is finalized. If there is a +// Reference pointing to this Reference then that case is handled by +// finalize_referred_to_object. +static void +finalize_reference (jobject ref) +{ + JvSynchronize sync (java::lang::ref::Reference::lock); + remove_from_hash (ref); + // The user might have a subclass of Reference with a finalizer. + _Jv_FinalizeObject (ref); +} + +void +_Jv_RegisterStringFinalizer (jobject str) +{ + // This function might be called before any other Reference method, + // so we must ensure the class is initialized. + _Jv_InitClass (&java::lang::ref::Reference::class$); + JvSynchronize sync (java::lang::ref::Reference::lock); + // If the object is in our hash table, then we might need to add a + // new FINALIZE entry. Otherwise, we just register an ordinary + // finalizer. + object_list *entry = in_hash (str); + if (entry) + maybe_add_finalize (entry, str); + else + _Jv_RegisterFinalizer ((void *) str, _Jv_FinalizeString); +} + +void +::java::lang::ref::Reference::create (jobject ref) +{ + // Nothing says you can't make a Reference with a NULL referent. + // But there's nothing to do in such a case. + referent = reinterpret_cast<gnu::gcj::RawData *> (ref); + copy = referent; + if (referent != NULL) + { + JvSynchronize sync (java::lang::ref::Reference::lock); + // `this' is a new Reference object. We register a new + // finalizer for pointed-to object and we arrange a special + // finalizer for ourselves as well. + _Jv_RegisterFinalizer (this, finalize_reference); + _Jv_RegisterFinalizer (referent, finalize_referred_to_object); + gnu::gcj::RawData **p = &referent; + _Jv_GCRegisterDisappearingLink ((jobject *) p); + add_to_hash (this); + } +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/Array.java b/gcc-4.2.1/libjava/java/lang/reflect/Array.java new file mode 100644 index 000000000..32bed06ee --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/Array.java @@ -0,0 +1,458 @@ +/* java.lang.reflect.Array - manipulate arrays by reflection + Copyright (C) 1998, 1999, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +import gnu.classpath.Configuration; + +/** + * Array holds static helper functions that allow you to create and + * manipulate arrays by reflection. Operations know how to perform widening + * conversions, but throw {@link IllegalArgumentException} if you attempt + * a narrowing conversion. Also, when accessing primitive arrays, this + * class performs object wrapping and unwrapping as necessary.<p> + * + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes. Note also that the shorthand <code>Object[].class</code> + * is a convenient way to get array Classes.<p> + * + * <B>Performance note:</B> This class performs best when it does not have + * to convert primitive types. The further along the chain it has to convert, + * the worse performance will be. You're best off using the array as whatever + * type it already is, and then converting the result. You will do even + * worse if you do this and use the generic set() function. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + * @author Per Bothner (bothner@cygnus.com) + * @see java.lang.Boolean#TYPE + * @see java.lang.Byte#TYPE + * @see java.lang.Short#TYPE + * @see java.lang.Character#TYPE + * @see java.lang.Integer#TYPE + * @see java.lang.Long#TYPE + * @see java.lang.Float#TYPE + * @see java.lang.Double#TYPE + * @since 1.1 + * @status updated to 1.4 + */ +public final class Array +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javalangreflect"); + } + } + + /** + * This class is uninstantiable. + */ + private Array() + { + } + + /** + * Creates a new single-dimensioned array. + * @param componentType the type of the array to create + * @param length the length of the array to create + * @return the created array, cast to an Object + * @throws NullPointerException if <code>componentType</code> is null + * @throws IllegalArgumentException if <code>componentType</code> is + * <code>Void.TYPE</code> + * @throws NegativeArraySizeException when length is less than 0 + * @throws OutOfMemoryError if memory allocation fails + */ + public static native Object newInstance(Class componentType, int length); + + /** + * Creates a new multi-dimensioned array. The new array has the same + * component type as the argument class, and the number of dimensions + * in the new array is the sum of the dimensions of the argument class + * and the length of the argument dimensions. Virtual Machine limitations + * forbid too many dimensions (usually 255 is the maximum); but even + * 50 dimensions of 2 elements in each dimension would exceed your memory + * long beforehand! + * + * @param componentType the type of the array to create. + * @param dimensions the dimensions of the array to create. Each element + * in <code>dimensions</code> makes another dimension of the new + * array. Thus, <code>Array.newInstance(java.lang.Boolean, + * new int[]{1,2,3})</code> is the same as + * <code>new java.lang.Boolean[1][2][3]</code> + * @return the created array, cast to an Object + * @throws NullPointerException if componentType or dimension is null + * @throws IllegalArgumentException if the the size of + * <code>dimensions</code> is 0 or exceeds the maximum number of + * array dimensions in the VM; or if componentType is Void.TYPE + * @throws NegativeArraySizeException when any of the dimensions is less + * than 0 + * @throws OutOfMemoryError if memory allocation fails + */ + public static native Object newInstance(Class elementType, int[] dimensions); + + /** + * Gets the array length. + * @param array the array + * @return the length of the array + * @throws IllegalArgumentException if <code>array</code> is not an array + * @throws NullPointerException if <code>array</code> is null + */ + public static native int getLength(Object array); + + /** + * Gets an element of an array. Primitive elements will be wrapped in + * the corresponding class type. + * + * @param array the array to access + * @param index the array index to access + * @return the element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not an array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #getBoolean(Object, int) + * @see #getByte(Object, int) + * @see #getChar(Object, int) + * @see #getShort(Object, int) + * @see #getInt(Object, int) + * @see #getLong(Object, int) + * @see #getFloat(Object, int) + * @see #getDouble(Object, int) + */ + public static native Object get(Object array, int index); + + /** + * Gets an element of a boolean array. + * + * @param array the array to access + * @param index the array index to access + * @return the boolean element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a boolean + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native boolean getBoolean(Object array, int index); + + /** + * Gets an element of a byte array. + * + * @param array the array to access + * @param index the array index to access + * @return the byte element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native byte getByte(Object array, int index); + + /** + * Gets an element of a char array. + * + * @param array the array to access + * @param index the array index to access + * @return the char element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a char + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native char getChar(Object array, int index); + + /** + * Gets an element of a short array. + * + * @param array the array to access + * @param index the array index to access + * @return the short element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte + * or char array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native short getShort(Object array, int index); + + /** + * Gets an element of an int array. + * + * @param array the array to access + * @param index the array index to access + * @return the int element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, or int array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native int getInt(Object array, int index); + + /** + * Gets an element of a long array. + * + * @param array the array to access + * @param index the array index to access + * @return the long element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, int, or long array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native long getLong(Object array, int index); + + /** + * Gets an element of a float array. + * + * @param array the array to access + * @param index the array index to access + * @return the float element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, int, long, or float array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native float getFloat(Object array, int index); + + /** + * Gets an element of a double array. + * + * @param array the array to access + * @param index the array index to access + * @return the double element at <code>array[index]</code> + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * char, short, int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #get(Object, int) + */ + public static native double getDouble(Object array, int index); + + private static native Class getElementType(Object array, int index); + + private static native void set(Object array, int index, + Object value, Class elType); + + /** + * Sets an element of an array. If the array is primitive, then the new + * value is unwrapped and widened. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not an array, + * or the array is primitive and unwrapping value fails, or the + * value is not assignable to the array component type + * @throws NullPointerException if array is null, or if array is primitive + * and value is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #setBoolean(Object, int, boolean) + * @see #setByte(Object, int, byte) + * @see #setChar(Object, int, char) + * @see #setShort(Object, int, short) + * @see #setInt(Object, int, int) + * @see #setLong(Object, int, long) + * @see #setFloat(Object, int, float) + * @see #setDouble(Object, int, double) + */ + public static void set(Object array, int index, Object value) + { + Class elType = getElementType(array, index); + if (! elType.isPrimitive()) + set(array, index, value, elType); + else if (value instanceof Byte) + setByte(array, index, ((Byte) value).byteValue()); + else if (value instanceof Short) + setShort(array, index, ((Short) value).shortValue()); + else if (value instanceof Integer) + setInt(array, index, ((Integer) value).intValue()); + else if (value instanceof Long) + setLong(array, index, ((Long) value).longValue()); + else if (value instanceof Float) + setFloat(array, index, ((Float) value).floatValue()); + else if (value instanceof Double) + setDouble(array, index, ((Double) value).doubleValue()); + else if (value instanceof Character) + setChar(array, index, ((Character) value).charValue()); + else if (value instanceof Boolean) + setBoolean(array, index, ((Boolean) value).booleanValue()); + else + throw new IllegalArgumentException(); + } + + /** + * Sets an element of a boolean array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a boolean + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setBoolean(Object array, int index, boolean value); + + /** + * Sets an element of a byte array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a byte, + * short, int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setByte(Object array, int index, byte value); + + /** + * Sets an element of a char array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a char, + * int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setChar(Object array, int index, char value); + + /** + * Sets an element of a short array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a short, + * int, long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setShort(Object array, int index, short value); + + /** + * Sets an element of an int array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not an int, + * long, float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setInt(Object array, int index, int value); + + /** + * Sets an element of a long array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a long, + * float, or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setLong(Object array, int index, long value); + + /** + * Sets an element of a float array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a float + * or double array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setFloat(Object array, int index, float value); + + /** + * Sets an element of a double array. + * + * @param array the array to set a value of + * @param index the array index to set the value to + * @param value the value to set + * @throws IllegalArgumentException if <code>array</code> is not a double + * array + * @throws NullPointerException if <code>array</code> is null + * @throws ArrayIndexOutOfBoundsException if <code>index</code> is out of + * bounds + * @see #set(Object, int, Object) + */ + public static native void setDouble(Object array, int index, double value); +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/Constructor.java b/gcc-4.2.1/libjava/java/lang/reflect/Constructor.java new file mode 100644 index 000000000..68b2d3985 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/Constructor.java @@ -0,0 +1,398 @@ +/* java.lang.reflect.Constructor - reflection of Java constructors + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +import gnu.java.lang.reflect.MethodSignatureParser; + +/** + * The Constructor class represents a constructor of a class. It also allows + * dynamic creation of an object, via reflection. Invocation on Constructor + * objects knows how to do widening conversions, but throws + * {@link IllegalArgumentException} if a narrowing conversion would be + * necessary. You can query for information on this Constructor regardless + * of location, but construction access may be limited by Java language + * access controls. If you can't do it in the compiler, you can't normally + * do it here either.<p> + * + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes.<p> + * + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. + * + * @author John Keiser + * @author Eric Blake <ebb9@email.byu.edu> + * @author Tom Tromey <tromey@redhat.com> + * @see Member + * @see Class + * @see java.lang.Class#getConstructor(Class[]) + * @see java.lang.Class#getDeclaredConstructor(Class[]) + * @see java.lang.Class#getConstructors() + * @see java.lang.Class#getDeclaredConstructors() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Constructor extends AccessibleObject + implements Member, GenericDeclaration +{ + private static final int CONSTRUCTOR_MODIFIERS + = Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC; + + /** + * This class is uninstantiable except from native code. + */ + private Constructor () + { + } + + /** + * Gets the class that declared this constructor. + * @return the class that declared this member + */ + public Class getDeclaringClass() + { + return declaringClass; + } + + /** + * Gets the name of this constructor (the non-qualified name of the class + * it was declared in). + * @return the name of this constructor + */ + public String getName() + { + return declaringClass.getName(); + } + + /** + * Return the raw modifiers for this constructor. In particular + * this will include the synthetic and varargs bits. + * @return the constructor's modifiers + */ + private native int getModifiersInternal(); + + /** + * Gets the modifiers this constructor uses. Use the <code>Modifier</code> + * class to interpret the values. A constructor can only have a subset of the + * following modifiers: public, private, protected. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + public int getModifiers () + { + return getModifiersInternal() & CONSTRUCTOR_MODIFIERS; + } + + /** + * Return true if this constructor is synthetic, false otherwise. + * A synthetic member is one which is created by the compiler, + * and which does not appear in the user's source code. + * @since 1.5 + */ + public boolean isSynthetic() + { + return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; + } + + /** + * Return true if this is a varargs constructor, that is if + * the constructor takes a variable number of arguments. + * @since 1.5 + */ + public boolean isVarArgs() + { + return (getModifiersInternal() & Modifier.VARARGS) != 0; + } + + /** + * Get the parameter list for this constructor, in declaration order. If the + * constructor takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the constructor's parameters + */ + public Class[] getParameterTypes () + { + if (parameter_types == null) + getType (); + return (Class[]) parameter_types.clone(); + } + + /** + * Get the exception types this constructor says it throws, in no particular + * order. If the constructor has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the constructor's throws clause + */ + public Class[] getExceptionTypes () + { + if (exception_types == null) + getType(); + return (Class[]) exception_types.clone(); + } + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Constructors are semantically equivalent if they have the same + * declaring class and the same parameter list. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Constructor)) + return false; + Constructor c = (Constructor) obj; + return declaringClass == c.declaringClass && offset == c.offset; + } + + /** + * Get the hash code for the Constructor. The Constructor hash code is the + * hash code of the declaring class's name. + * + * @return the hash code for the object + */ + public int hashCode () + { + return declaringClass.getName().hashCode(); + } + + /** + * Get a String representation of the Constructor. A Constructor's String + * representation is "<modifier> <classname>(<paramtypes>) + * throws <exceptions>", where everything after ')' is omitted if + * there are no exceptions.<br> Example: + * <code>public java.io.FileInputStream(java.lang.Runnable) + * throws java.io.FileNotFoundException</code> + * + * @return the String representation of the Constructor + */ + public String toString() + { + if (parameter_types == null) + getType (); + StringBuffer b = new StringBuffer (); + int mods = getModifiers(); + if (mods != 0) + { + Modifier.toString(mods, b); + b.append(" "); + } + Method.appendClassName (b, declaringClass); + b.append("("); + for (int i = 0; i < parameter_types.length; ++i) + { + Method.appendClassName (b, parameter_types[i]); + if (i < parameter_types.length - 1) + b.append(","); + } + b.append(")"); + return b.toString(); + } + + /* FIXME[GENERICS]: Add X extends GenericDeclaration and TypeVariable<X> */ + static void addTypeParameters(StringBuilder sb, TypeVariable[] typeArgs) + { + if (typeArgs.length == 0) + return; + sb.append('<'); + for (int i = 0; i < typeArgs.length; ++i) + { + if (i > 0) + sb.append(','); + sb.append(typeArgs[i]); + } + sb.append("> "); + } + + public String toGenericString() + { + StringBuilder sb = new StringBuilder(128); + Modifier.toString(getModifiers(), sb).append(' '); + addTypeParameters(sb, getTypeParameters()); + sb.append(getDeclaringClass().getName()).append('('); + Type[] types = getGenericParameterTypes(); + if (types.length > 0) + { + sb.append(types[0]); + for (int i = 1; i < types.length; ++i) + sb.append(',').append(types[i]); + } + sb.append(')'); + types = getGenericExceptionTypes(); + if (types.length > 0) + { + sb.append(" throws ").append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } + return sb.toString(); + } + + /** + * Create a new instance by invoking the constructor. Arguments are + * automatically unwrapped and widened, if needed.<p> + * + * If this class is abstract, you will get an + * <code>InstantiationException</code>. If the constructor takes 0 + * arguments, you may use null or a 0-length array for <code>args</code>.<p> + * + * If this Constructor enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not create this object in similar compiled code. If the class + * is uninitialized, you trigger class initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Then, the constructor is invoked. If it completes normally, the return + * value will be the new object. If it completes abruptly, the exception is + * wrapped in an <code>InvocationTargetException</code>. + * + * @param args the arguments to the constructor + * @return the newly created object + * @throws IllegalAccessException if the constructor could not normally be + * called by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * or if the arguments types are wrong even with a widening + * conversion + * @throws InstantiationException if the class is abstract + * @throws InvocationTargetException if the constructor throws an exception + * @throws ExceptionInInitializerError if construction triggered class + * initialization, which then failed + */ + public native Object newInstance (Object[] args) + throws InstantiationException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException; + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this constructor, in declaration order. + * An array of size zero is returned if this constructor has no type + * variables. + * + * @return the type variables associated with this constructor. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /* FIXME[GENERICS]: Add <Constructor<T>> */ + public TypeVariable[] getTypeParameters() + { + String sig = getSignature(); + if (sig == null) + return new TypeVariable[0]; + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Return the String in the Signature attribute for this constructor. If there + * is no Signature attribute, return null. + */ + private String getSignature() + { + // FIXME: libgcj doesn't record this information yet. + return null; + } + + /** + * Returns an array of <code>Type</code> objects that represents + * the exception types declared by this constructor, in declaration order. + * An array of size zero is returned if this constructor declares no + * exceptions. + * + * @return the exception types declared by this constructor. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type[] getGenericExceptionTypes() + { + String sig = getSignature(); + if (sig == null) + return getExceptionTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericExceptionTypes(); + } + + /** + * Returns an array of <code>Type</code> objects that represents + * the parameter list for this constructor, in declaration order. + * An array of size zero is returned if this constructor takes no + * parameters. + * + * @return a list of the types of the constructor's parameters + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type[] getGenericParameterTypes() + { + String sig = getSignature(); + if (sig == null) + return getParameterTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericParameterTypes(); + } + + // Update cached values from method descriptor in class. + private native void getType (); + + // Declaring class. + private Class declaringClass; + + // Exception types. + private Class[] exception_types; + // Parameter types. + private Class[] parameter_types; + + // Offset in bytes from the start of declaringClass's methods array. + private int offset; +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/Field.java b/gcc-4.2.1/libjava/java/lang/reflect/Field.java new file mode 100644 index 000000000..134ff132e --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/Field.java @@ -0,0 +1,801 @@ +/* java.lang.reflect.Field - reflection of Java fields + Copyright (C) 1998, 2001, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +import gnu.java.lang.ClassHelper; + +import gnu.java.lang.reflect.FieldSignatureParser; + +/** + * The Field class represents a member variable of a class. It also allows + * dynamic access to a member, via reflection. This works for both + * static and instance fields. Operations on Field objects know how to + * do widening conversions, but throw {@link IllegalArgumentException} if + * a narrowing conversion would be necessary. You can query for information + * on this Field regardless of location, but get and set access may be limited + * by Java language access controls. If you can't do it in the compiler, you + * can't normally do it here either.<p> + * + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes.<p> + * + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. + * + * @author John Keiser + * @author Eric Blake <ebb9@email.byu.edu> + * @author Per Bothner <bothner@cygnus.com> + * @see Member + * @see Class + * @see Class#getField(String) + * @see Class#getDeclaredField(String) + * @see Class#getFields() + * @see Class#getDeclaredFields() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Field + extends AccessibleObject implements Member +{ + private Class declaringClass; + private String name; + + // Offset in bytes from the start of declaringClass's fields array. + private int offset; + + // The Class (or primitive TYPE) of this field. + private Class type; + + private static final int FIELD_MODIFIERS + = Modifier.FINAL | Modifier.PRIVATE | Modifier.PROTECTED + | Modifier.PUBLIC | Modifier.STATIC | Modifier.TRANSIENT + | Modifier.VOLATILE; + + // This is instantiated by Class sometimes, but it uses C++ and + // avoids the Java protection check. + Field () + { + } + + /** + * Gets the class that declared this field, or the class where this field + * is a non-inherited member. + * @return the class that declared this member + */ + public Class getDeclaringClass() + { + return declaringClass; + } + + /** + * Gets the name of this field. + * @return the name of this field + */ + public native String getName(); + + /** + * Return the raw modifiers for this field. + * @return the field's modifiers + */ + private native int getModifiersInternal(); + + /** + * Gets the modifiers this field uses. Use the <code>Modifier</code> + * class to interpret the values. A field can only have a subset of the + * following modifiers: public, private, protected, static, final, + * transient, and volatile. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + public int getModifiers() + { + return getModifiersInternal() & FIELD_MODIFIERS; + } + + /** + * Return true if this field is synthetic, false otherwise. + * @since 1.5 + */ + public boolean isSynthetic() + { + return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; + } + + /** + * Return true if this field represents an enum constant, + * false otherwise. + * @since 1.5 + */ + public boolean isEnumConstant() + { + return (getModifiersInternal() & Modifier.ENUM) != 0; + } + + /** + * Gets the type of this field. + * @return the type of this field + */ + public native Class getType(); + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Fields are semantically equivalent if they have the same declaring + * class, name, and type. Since you can't creat a Field except through + * the VM, this is just the == relation. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not + */ + public boolean equals (Object fld) + { + if (! (fld instanceof Field)) + return false; + Field f = (Field) fld; + return declaringClass == f.declaringClass && offset == f.offset; + } + + /** + * Get the hash code for the Field. The Field hash code is the hash code + * of its name XOR'd with the hash code of its class name. + * + * @return the hash code for the object. + */ + public int hashCode() + { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); + } + + /** + * Get a String representation of the Field. A Field's String + * representation is "<modifiers> <type> + * <class>.<fieldname>".<br> Example: + * <code>public transient boolean gnu.parse.Parser.parseComplete</code> + * + * @return the String representation of the Field + */ + public String toString () + { + StringBuffer sbuf = new StringBuffer (); + int mods = getModifiers(); + if (mods != 0) + { + Modifier.toString(mods, sbuf); + sbuf.append(' '); + } + Method.appendClassName (sbuf, getType ()); + sbuf.append(' '); + Method.appendClassName (sbuf, getDeclaringClass()); + sbuf.append('.'); + sbuf.append(getName()); + return sbuf.toString(); + } + + public String toGenericString() + { + StringBuilder sb = new StringBuilder(64); + Modifier.toString(getModifiers(), sb).append(' '); + sb.append(getGenericType()).append(' '); + sb.append(getDeclaringClass().getName()).append('.'); + sb.append(getName()); + return sb.toString(); + } + + /** + * Get the value of this Field. If it is primitive, it will be wrapped + * in the appropriate wrapper type (boolean = java.lang.Boolean).<p> + * + * If the field is static, <code>o</code> will be ignored. Otherwise, if + * <code>o</code> is null, you get a <code>NullPointerException</code>, + * and if it is incompatible with the declaring class of the field, you + * get an <code>IllegalArgumentException</code>.<p> + * + * Next, if this Field enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not access this field in similar compiled code. If the field + * is static, and its class is uninitialized, you trigger class + * initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Finally, the field is accessed, and primitives are wrapped (but not + * necessarily in new objects). This method accesses the field of the + * declaring class, even if the instance passed in belongs to a subclass + * which declares another field to hide this one. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if <code>o</code> is not an instance of + * the class or interface declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #getBoolean(Object) + * @see #getByte(Object) + * @see #getChar(Object) + * @see #getShort(Object) + * @see #getInt(Object) + * @see #getLong(Object) + * @see #getFloat(Object) + * @see #getDouble(Object) + */ + public Object get(Object obj) + throws IllegalAccessException + { + return get(null, obj); + } + + /** + * Get the value of this boolean Field. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a boolean field of + * <code>o</code>, or if <code>o</code> is not an instance of the + * declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public boolean getBoolean(Object obj) + throws IllegalAccessException + { + return getBoolean(null, obj); + } + + /** + * Get the value of this byte Field. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte field of + * <code>o</code>, or if <code>o</code> is not an instance of the + * declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public byte getByte(Object obj) + throws IllegalAccessException + { + return getByte(null, obj); + } + + /** + * Get the value of this Field as a char. If the field is static, + * <code>o</code> will be ignored. + * + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a char field of + * <code>o</code>, or if <code>o</code> is not an instance + * of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public char getChar(Object obj) + throws IllegalAccessException + { + return getChar(null, obj); + } + + /** + * Get the value of this Field as a short. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte or short + * field of <code>o</code>, or if <code>o</code> is not an instance + * of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public short getShort(Object obj) + throws IllegalAccessException + { + return getShort(null, obj); + } + + /** + * Get the value of this Field as an int. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, or + * int field of <code>o</code>, or if <code>o</code> is not an + * instance of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public int getInt(Object obj) + throws IllegalAccessException + { + return getInt(null, obj); + } + + /** + * Get the value of this Field as a long. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, int, + * or long field of <code>o</code>, or if <code>o</code> is not an + * instance of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public long getLong(Object obj) + throws IllegalAccessException + { + return getLong(null, obj); + } + + /** + * Get the value of this Field as a float. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, int, + * long, or float field of <code>o</code>, or if <code>o</code> is + * not an instance of the declaring class of this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public float getFloat(Object obj) + throws IllegalAccessException + { + return getFloat(null, obj); + } + + /** + * Get the value of this Field as a double. If the field is static, + * <code>o</code> will be ignored. + * + * @param o the object to get the value of this Field from + * @return the value of the Field + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, char, int, + * long, float, or double field of <code>o</code>, or if + * <code>o</code> is not an instance of the declaring class of this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #get(Object) + */ + public double getDouble(Object obj) + throws IllegalAccessException + { + return getDouble(null, obj); + } + + private native boolean getBoolean (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native char getChar (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native byte getByte (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native short getShort (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native int getInt (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native long getLong (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native float getFloat (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native double getDouble (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + private native Object get (Class caller, Object obj) + throws IllegalArgumentException, IllegalAccessException; + + /** + * Set the value of this Field. If it is a primitive field, the value + * will be unwrapped from the passed object (boolean = java.lang.Boolean).<p> + * + * If the field is static, <code>o</code> will be ignored. Otherwise, if + * <code>o</code> is null, you get a <code>NullPointerException</code>, + * and if it is incompatible with the declaring class of the field, you + * get an <code>IllegalArgumentException</code>.<p> + * + * Next, if this Field enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not access this field in similar compiled code. This also + * occurs whether or not there is access control if the field is final. + * If the field is primitive, and unwrapping your argument fails, you will + * get an <code>IllegalArgumentException</code>; likewise, this error + * happens if <code>value</code> cannot be cast to the correct object type. + * If the field is static, and its class is uninitialized, you trigger class + * initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Finally, the field is set with the widened value. This method accesses + * the field of the declaring class, even if the instance passed in belongs + * to a subclass which declares another field to hide this one. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if <code>value</code> cannot be + * converted by a widening conversion to the underlying type of + * the Field, or if <code>o</code> is not an instance of the class + * declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #setBoolean(Object, boolean) + * @see #setByte(Object, byte) + * @see #setChar(Object, char) + * @see #setShort(Object, short) + * @see #setInt(Object, int) + * @see #setLong(Object, long) + * @see #setFloat(Object, float) + * @see #setDouble(Object, double) + */ + public void set(Object object, Object value) + throws IllegalAccessException + { + set(null, object, value); + } + + /** + * Set this boolean Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a boolean field, or if + * <code>o</code> is not an instance of the class declaring this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setBoolean(Object obj, boolean b) + throws IllegalAccessException + { + setBoolean(null, obj, b, true); + } + + /** + * Set this byte Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a byte, short, int, long, + * float, or double field, or if <code>o</code> is not an instance + * of the class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setByte(Object obj, byte b) + throws IllegalAccessException + { + setByte(null, obj, b, true); + } + + /** + * Set this char Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a char, int, long, + * float, or double field, or if <code>o</code> is not an instance + * of the class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setChar(Object obj, char c) + throws IllegalAccessException + { + setChar(null, obj, c, true); + } + + /** + * Set this short Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a short, int, long, + * float, or double field, or if <code>o</code> is not an instance + * of the class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setShort(Object obj, short s) + throws IllegalAccessException + { + setShort(null, obj, s, true); + } + + /** + * Set this int Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not an int, long, float, or + * double field, or if <code>o</code> is not an instance of the + * class declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setInt(Object obj, int i) + throws IllegalAccessException + { + setInt(null, obj, i, true); + } + + /** + * Set this long Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a long, float, or double + * field, or if <code>o</code> is not an instance of the class + * declaring this field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setLong(Object obj, long l) + throws IllegalArgumentException, IllegalAccessException + { + setLong(null, obj, l, true); + } + + /** + * Set this float Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a float or long field, or + * if <code>o</code> is not an instance of the class declaring this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setFloat(Object obj, float f) + throws IllegalAccessException + { + setFloat(null, obj, f, true); + } + + /** + * Set this double Field. If the field is static, <code>o</code> will be + * ignored. + * + * @param o the object to set this Field on + * @param value the value to set this Field to + * @throws IllegalAccessException if you could not normally access this field + * (i.e. it is not public) + * @throws IllegalArgumentException if this is not a double field, or if + * <code>o</code> is not an instance of the class declaring this + * field + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static field triggered + * class initialization, which then failed + * @see #set(Object, Object) + */ + public void setDouble(Object obj, double d) + throws IllegalAccessException + { + setDouble(null, obj, d, true); + } + + /** + * Return the generic type of the field. If the field type is not a generic + * type, the method returns the same as <code>getType()</code>. + * + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type getGenericType() + { + String signature = getSignature(); + if (signature == null) + return getType(); + FieldSignatureParser p = new FieldSignatureParser(getDeclaringClass(), + signature); + return p.getFieldType(); + } + + /** + * Return the String in the Signature attribute for this field. If there + * is no Signature attribute, return null. + */ + private String getSignature() + { + // FIXME: libgcj doesn't record Signature attributes yet. + return null; + } + + native void setByte (Class caller, Object obj, byte b, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setShort (Class caller, Object obj, short s, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setInt (Class caller, Object obj, int i, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setLong (Class caller, Object obj, long l, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setFloat (Class caller, Object obj, float f, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setDouble (Class caller, Object obj, double d, + boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setChar (Class caller, Object obj, char c, boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void setBoolean (Class caller, Object obj, boolean b, + boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + native void set (Class caller, Object obj, Object val, Class type, + boolean checkFinal) + throws IllegalArgumentException, IllegalAccessException; + + private void set (Class caller, Object object, Object value) + throws IllegalArgumentException, IllegalAccessException + { + Class type = getType(); + if (! type.isPrimitive()) + set(caller, object, value, type, true); + else if (value instanceof Byte) + setByte(caller, object, ((Byte) value).byteValue(), true); + else if (value instanceof Short) + setShort (caller, object, ((Short) value).shortValue(), true); + else if (value instanceof Integer) + setInt(caller, object, ((Integer) value).intValue(), true); + else if (value instanceof Long) + setLong(caller, object, ((Long) value).longValue(), true); + else if (value instanceof Float) + setFloat(caller, object, ((Float) value).floatValue(), true); + else if (value instanceof Double) + setDouble(caller, object, ((Double) value).doubleValue(), true); + else if (value instanceof Character) + setChar(caller, object, ((Character) value).charValue(), true); + else if (value instanceof Boolean) + setBoolean(caller, object, ((Boolean) value).booleanValue(), true); + else + throw new IllegalArgumentException(); + } +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/Method.java b/gcc-4.2.1/libjava/java/lang/reflect/Method.java new file mode 100644 index 000000000..3142d6494 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/Method.java @@ -0,0 +1,444 @@ +// Method.java - Represent method of class or interface. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +package java.lang.reflect; + +import gnu.gcj.RawData; +import gnu.java.lang.reflect.MethodSignatureParser; + +/** + * The Method class represents a member method of a class. It also allows + * dynamic invocation, via reflection. This works for both static and + * instance methods. Invocation on Method objects knows how to do + * widening conversions, but throws {@link IllegalArgumentException} if + * a narrowing conversion would be necessary. You can query for information + * on this Method regardless of location, but invocation access may be limited + * by Java language access controls. If you can't do it in the compiler, you + * can't normally do it here either.<p> + * + * <B>Note:</B> This class returns and accepts types as Classes, even + * primitive types; there are Class types defined that represent each + * different primitive type. They are <code>java.lang.Boolean.TYPE, + * java.lang.Byte.TYPE,</code>, also available as <code>boolean.class, + * byte.class</code>, etc. These are not to be confused with the + * classes <code>java.lang.Boolean, java.lang.Byte</code>, etc., which are + * real classes.<p> + * + * Also note that this is not a serializable class. It is entirely feasible + * to make it serializable using the Externalizable interface, but this is + * on Sun, not me. + * + * @author John Keiser + * @author Eric Blake <ebb9@email.byu.edu> + * @author Tom Tromey <tromey@redhat.com> + * @see Member + * @see Class + * @see java.lang.Class#getMethod(String,Class[]) + * @see java.lang.Class#getDeclaredMethod(String,Class[]) + * @see java.lang.Class#getMethods() + * @see java.lang.Class#getDeclaredMethods() + * @since 1.1 + * @status updated to 1.4 + */ +public final class Method + extends AccessibleObject implements Member, GenericDeclaration +{ + private static final int METHOD_MODIFIERS + = Modifier.ABSTRACT | Modifier.FINAL | Modifier.NATIVE + | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC + | Modifier.STATIC | Modifier.STRICT | Modifier.SYNCHRONIZED; + + /** + * This class is uninstantiable. + */ + private Method () + { + } + + /** + * Gets the class that declared this method, or the class where this method + * is a non-inherited member. + * @return the class that declared this member + */ + public Class getDeclaringClass() + { + return declaringClass; + } + + /** + * Gets the name of this method. + * @return the name of this method + */ + public native String getName (); + + /** + * Return the raw modifiers for this method. + * @return the method's modifiers + */ + private native int getModifiersInternal(); + + /** + * Gets the modifiers this method uses. Use the <code>Modifier</code> + * class to interpret the values. A method can only have a subset of the + * following modifiers: public, private, protected, abstract, static, + * final, synchronized, native, and strictfp. + * + * @return an integer representing the modifiers to this Member + * @see Modifier + */ + public int getModifiers() + { + return getModifiersInternal() & METHOD_MODIFIERS; + } + + /** + * Return true if this method is a bridge method. A bridge method + * is generated by the compiler in some situations involving + * generics and inheritance. + * @since 1.5 + */ + public boolean isBridge() + { + return (getModifiersInternal() & Modifier.BRIDGE) != 0; + } + + /** + * Return true if this method is synthetic, false otherwise. + * @since 1.5 + */ + public boolean isSynthetic() + { + return (getModifiersInternal() & Modifier.SYNTHETIC) != 0; + } + + /** + * Return true if this is a varargs method, that is if + * the method takes a variable number of arguments. + * @since 1.5 + */ + public boolean isVarArgs() + { + return (getModifiersInternal() & Modifier.VARARGS) != 0; + } + + /** + * Gets the return type of this method. + * @return the type of this method + */ + public Class getReturnType () + { + if (return_type == null) + getType(); + return return_type; + } + + /** + * Get the parameter list for this method, in declaration order. If the + * method takes no parameters, returns a 0-length array (not null). + * + * @return a list of the types of the method's parameters + */ + public Class[] getParameterTypes () + { + if (parameter_types == null) + getType(); + return (Class[]) parameter_types.clone(); + } + + /** + * Get the exception types this method says it throws, in no particular + * order. If the method has no throws clause, returns a 0-length array + * (not null). + * + * @return a list of the types in the method's throws clause + */ + public Class[] getExceptionTypes () + { + if (exception_types == null) + getType(); + return (Class[]) exception_types.clone(); + } + + /** + * Compare two objects to see if they are semantically equivalent. + * Two Methods are semantically equivalent if they have the same declaring + * class, name, and parameter list. This ignores different exception + * clauses or return types. + * + * @param o the object to compare to + * @return <code>true</code> if they are equal; <code>false</code> if not + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Method)) + return false; + Method m = (Method) obj; + return declaringClass == m.declaringClass && offset == m.offset; + } + + /** + * Get the hash code for the Method. The Method hash code is the hash code + * of its name XOR'd with the hash code of its class name. + * + * @return the hash code for the object + */ + public int hashCode() + { + return getDeclaringClass().getName().hashCode() ^ getName().hashCode(); + } + + /** + * Get a String representation of the Method. A Method's String + * representation is "<modifiers> <returntype> + * <methodname>(<paramtypes>) throws <exceptions>", where + * everything after ')' is omitted if there are no exceptions.<br> Example: + * <code>public static int run(java.lang.Runnable,int)</code> + * + * @return the String representation of the Method + */ + public String toString() + { + if (parameter_types == null) + getType (); + + StringBuffer b = new StringBuffer (); + int mods = getModifiers(); + if (mods != 0) + { + Modifier.toString(mods, b); + b.append(" "); + } + appendClassName (b, return_type); + b.append(" "); + appendClassName (b, declaringClass); + b.append("."); + b.append(getName()); + b.append("("); + for (int i = 0; i < parameter_types.length; ++i) + { + appendClassName (b, parameter_types[i]); + if (i < parameter_types.length - 1) + b.append(","); + } + b.append(")"); + if (exception_types.length > 0) + { + b.append(" throws "); + for (int i = 0; i < exception_types.length; ++i) + { + appendClassName (b, exception_types[i]); + if (i < exception_types.length - 1) + b.append(","); + } + } + return b.toString(); + } + + public String toGenericString() + { + // 128 is a reasonable buffer initial size for constructor + StringBuilder sb = new StringBuilder(128); + Modifier.toString(getModifiers(), sb).append(' '); + Constructor.addTypeParameters(sb, getTypeParameters()); + sb.append(getGenericReturnType()).append(' '); + sb.append(getDeclaringClass().getName()).append('.'); + sb.append(getName()).append('('); + Type[] types = getGenericParameterTypes(); + if (types.length > 0) + { + sb.append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } + sb.append(')'); + types = getGenericExceptionTypes(); + if (types.length > 0) + { + sb.append(" throws ").append(types[0]); + for (int i = 1; i < types.length; i++) + sb.append(',').append(types[i]); + } + return sb.toString(); + } + + /** + * Invoke the method. Arguments are automatically unwrapped and widened, + * and the result is automatically wrapped, if needed.<p> + * + * If the method is static, <code>o</code> will be ignored. Otherwise, + * the method uses dynamic lookup as described in JLS 15.12.4.4. You cannot + * mimic the behavior of nonvirtual lookup (as in super.foo()). This means + * you will get a <code>NullPointerException</code> if <code>o</code> is + * null, and an <code>IllegalArgumentException</code> if it is incompatible + * with the declaring class of the method. If the method takes 0 arguments, + * you may use null or a 0-length array for <code>args</code>.<p> + * + * Next, if this Method enforces access control, your runtime context is + * evaluated, and you may have an <code>IllegalAccessException</code> if + * you could not acces this method in similar compiled code. If the method + * is static, and its class is uninitialized, you trigger class + * initialization, which may end in a + * <code>ExceptionInInitializerError</code>.<p> + * + * Finally, the method is invoked. If it completes normally, the return value + * will be null for a void method, a wrapped object for a primitive return + * method, or the actual return of an Object method. If it completes + * abruptly, the exception is wrapped in an + * <code>InvocationTargetException</code>. + * + * @param o the object to invoke the method on + * @param args the arguments to the method + * @return the return value of the method, wrapped in the appropriate + * wrapper if it is primitive + * @throws IllegalAccessException if the method could not normally be called + * by the Java code (i.e. it is not public) + * @throws IllegalArgumentException if the number of arguments is incorrect; + * if the arguments types are wrong even with a widening conversion; + * or if <code>o</code> is not an instance of the class or interface + * declaring this method + * @throws InvocationTargetException if the method throws an exception + * @throws NullPointerException if <code>o</code> is null and this field + * requires an instance + * @throws ExceptionInInitializerError if accessing a static method triggered + * class initialization, which then failed + */ + public native Object invoke (Object obj, Object[] args) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException; + + /** + * Returns an array of <code>TypeVariable</code> objects that represents + * the type variables declared by this constructor, in declaration order. + * An array of size zero is returned if this class has no type + * variables. + * + * @return the type variables associated with this class. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + /* FIXME[GENERICS]: Should be TypeVariable<Method>[] */ + public TypeVariable[] getTypeParameters() + { + String sig = getSignature(); + if (sig == null) + return new TypeVariable[0]; + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getTypeParameters(); + } + + /** + * Return the String in the Signature attribute for this method. If there + * is no Signature attribute, return null. + */ + private String getSignature() + { + // FIXME: libgcj doesn't record this information yet. + return null; + } + + /** + * Returns an array of <code>Type</code> objects that represents + * the exception types declared by this method, in declaration order. + * An array of size zero is returned if this method declares no + * exceptions. + * + * @return the exception types declared by this method. + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type[] getGenericExceptionTypes() + { + String sig = getSignature(); + if (sig == null) + return getExceptionTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericExceptionTypes(); + } + + /** + * Returns an array of <code>Type</code> objects that represents + * the parameter list for this method, in declaration order. + * An array of size zero is returned if this method takes no + * parameters. + * + * @return a list of the types of the method's parameters + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type[] getGenericParameterTypes() + { + String sig = getSignature(); + if (sig == null) + return getParameterTypes(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericParameterTypes(); + } + + /** + * Returns the return type of this method. + * + * @return the return type of this method + * @throws GenericSignatureFormatError if the generic signature does + * not conform to the format specified in the Virtual Machine + * specification, version 3. + * @since 1.5 + */ + public Type getGenericReturnType() + { + String sig = getSignature(); + if (sig == null) + return getReturnType(); + MethodSignatureParser p = new MethodSignatureParser(this, sig); + return p.getGenericReturnType(); + } + + private native void getType (); + + // Append a class name to a string buffer. We try to print the + // fully-qualified name, the way that a Java programmer would expect + // it to be written. Weirdly, Class has no appropriate method for + // this. + static void appendClassName (StringBuffer buf, Class k) + { + if (k.isArray ()) + { + appendClassName (buf, k.getComponentType ()); + buf.append ("[]"); + } + else + { + // This is correct for primitive and reference types. Really + // we'd like `Main$Inner' to be printed as `Main.Inner', I + // think, but that is a pain. + buf.append (k.getName ()); + } + } + + // Declaring class. + private Class declaringClass; + + // Exception types. + private Class[] exception_types; + // Name cache. (Initially null.) + private String name; + // Parameter types. + private Class[] parameter_types; + // Return type. + private Class return_type; + + // Offset in bytes from the start of declaringClass's methods array. + private int offset; +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/Modifier.java b/gcc-4.2.1/libjava/java/lang/reflect/Modifier.java new file mode 100644 index 000000000..f9a9ca2c9 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/Modifier.java @@ -0,0 +1,375 @@ +/* java.lang.reflect.Modifier + Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +/** + * Modifier is a helper class with static methods to determine whether an + * int returned from getModifiers() represents static, public, protected, + * native, final, etc... and provides an additional method to print + * out all of the modifiers in an int in order. + * <p> + * The methods in this class use the bitmask values in the VM spec to + * determine the modifiers of an int. This means that a VM must return a + * standard mask, conformant with the VM spec. I don't know if this is how + * Sun does it, but I'm willing to bet money that it is. + * + * @author John Keiser + * @author Tom Tromey (tromey@cygnus.com) + * @author Eric Blake (ebb9@email.byu.edu) + * @see Member#getModifiers() + * @see Method#getModifiers() + * @see Field#getModifiers() + * @see Constructor#getModifiers() + * @see Class#getModifiers() + * @since 1.1 + */ +public class Modifier +{ + /** <STRONG>This constructor really shouldn't be here ... there are no + * instance methods or variables of this class, so instantiation is + * worthless. However, this function is in the 1.1 spec, so it is added + * for completeness.</STRONG> + */ + public Modifier() + { + } + + /** + * Public: accessible from any other class. + */ + public static final int PUBLIC = 0x0001; + + /** + * Private: accessible only from the same enclosing class. + */ + public static final int PRIVATE = 0x0002; + + /** + * Protected: accessible only to subclasses, or within the package. + */ + public static final int PROTECTED = 0x0004; + + /** + * Static:<br><ul> + * <li>Class: no enclosing instance for nested class.</li> + * <li>Field or Method: can be accessed or invoked without an + * instance of the declaring class.</li> + * </ul> + */ + public static final int STATIC = 0x0008; + + /** + * Final:<br><ul> + * <li>Class: no subclasses allowed.</li> + * <li>Field: cannot be changed.</li> + * <li>Method: cannot be overriden.</li> + * </ul> + */ + public static final int FINAL = 0x0010; + + /** + * Synchronized: Method: lock the class while calling this method. + */ + public static final int SYNCHRONIZED = 0x0020; + + /** + * Volatile: Field: cannot be cached. + */ + public static final int VOLATILE = 0x0040; + + /** + * Transient: Field: not serialized or deserialized. + */ + public static final int TRANSIENT = 0x0080; + + /** + * Native: Method: use JNI to call this method. + */ + public static final int NATIVE = 0x0100; + + /** + * Interface: Class: is an interface. + */ + public static final int INTERFACE = 0x0200; + + /** + * Abstract:<br><ul> + * <li>Class: may not be instantiated.</li> + * <li>Method: may not be called.</li> + * </ul> + */ + public static final int ABSTRACT = 0x0400; + + /** + * Strictfp: Method: expressions are FP-strict.<p> + * Also used as a modifier for classes, to mean that all initializers + * and constructors are FP-strict, but does not show up in + * Class.getModifiers. + */ + public static final int STRICT = 0x0800; + + + /** + * Super - treat invokespecial as polymorphic so that super.foo() works + * according to the JLS. This is a reuse of the synchronized constant + * to patch a hole in JDK 1.0. *shudder*. + */ + static final int SUPER = 0x0020; + + /** + * All the flags, only used by code in this package. + */ + static final int ALL_FLAGS = 0xfff; + + /** + * Flag indicating a bridge method. + */ + static final int BRIDGE = 0x40; + + /** + * Flag indicating a varargs method. + */ + static final int VARARGS = 0x80; + + /** + * Flag indicating a synthetic member. + */ + static final int SYNTHETIC = 0x1000; + + /** + * Flag indicating an enum constant or an enum class. + */ + static final int ENUM = 0x4000; + + /** + * GCJ-LOCAL: This access flag is set on methods we declare + * internally but which must not be visible to reflection. + */ + static final int INVISIBLE = 0x8000; + + /** + * GCJ-LOCAL: This access flag is set on interpreted classes. + */ + static final int INTERPRETED = 0x1000; + + /** + * Check whether the given modifier is abstract. + * @param mod the modifier. + * @return <code>true</code> if abstract, <code>false</code> otherwise. + */ + public static boolean isAbstract(int mod) + { + return (mod & ABSTRACT) != 0; + } + + /** + * Check whether the given modifier is final. + * @param mod the modifier. + * @return <code>true</code> if final, <code>false</code> otherwise. + */ + public static boolean isFinal(int mod) + { + return (mod & FINAL) != 0; + } + + /** + * Check whether the given modifier is an interface. + * @param mod the modifier. + * @return <code>true</code> if an interface, <code>false</code> otherwise. + */ + public static boolean isInterface(int mod) + { + return (mod & INTERFACE) != 0; + } + + /** + * Check whether the given modifier is native. + * @param mod the modifier. + * @return <code>true</code> if native, <code>false</code> otherwise. + */ + public static boolean isNative(int mod) + { + return (mod & NATIVE) != 0; + } + + /** + * Check whether the given modifier is private. + * @param mod the modifier. + * @return <code>true</code> if private, <code>false</code> otherwise. + */ + public static boolean isPrivate(int mod) + { + return (mod & PRIVATE) != 0; + } + + /** + * Check whether the given modifier is protected. + * @param mod the modifier. + * @return <code>true</code> if protected, <code>false</code> otherwise. + */ + public static boolean isProtected(int mod) + { + return (mod & PROTECTED) != 0; + } + + /** + * Check whether the given modifier is public. + * @param mod the modifier. + * @return <code>true</code> if public, <code>false</code> otherwise. + */ + public static boolean isPublic(int mod) + { + return (mod & PUBLIC) != 0; + } + + /** + * Check whether the given modifier is static. + * @param mod the modifier. + * @return <code>true</code> if static, <code>false</code> otherwise. + */ + public static boolean isStatic(int mod) + { + return (mod & STATIC) != 0; + } + + /** + * Check whether the given modifier is strictfp. + * @param mod the modifier. + * @return <code>true</code> if strictfp, <code>false</code> otherwise. + */ + public static boolean isStrict(int mod) + { + return (mod & STRICT) != 0; + } + + /** + * Check whether the given modifier is synchronized. + * @param mod the modifier. + * @return <code>true</code> if synchronized, <code>false</code> otherwise. + */ + public static boolean isSynchronized(int mod) + { + return (mod & SYNCHRONIZED) != 0; + } + + /** + * Check whether the given modifier is transient. + * @param mod the modifier. + * @return <code>true</code> if transient, <code>false</code> otherwise. + */ + public static boolean isTransient(int mod) + { + return (mod & TRANSIENT) != 0; + } + + /** + * Check whether the given modifier is volatile. + * @param mod the modifier. + * @return <code>true</code> if volatile, <code>false</code> otherwise. + */ + public static boolean isVolatile(int mod) + { + return (mod & VOLATILE) != 0; + } + + /** + * Get a string representation of all the modifiers represented by the + * given int. The keywords are printed in this order: + * <code><public|protected|private> abstract static final transient + * volatile synchronized native strictfp interface</code>. + * + * @param mod the modifier. + * @return the String representing the modifiers. + */ + public static String toString(int mod) + { + return toString(mod, new StringBuffer()).toString(); + } + + /** + * Package helper method that can take a StringBuilder. + * @param mod the modifier + * @param r the StringBuilder to which the String representation is appended + * @return r, with information appended + */ + static StringBuilder toString(int mod, StringBuilder r) + { + r.append(toString(mod, new StringBuffer())); + return r; + } + + /** + * Package helper method that can take a StringBuffer. + * @param mod the modifier + * @param r the StringBuffer to which the String representation is appended + * @return r, with information appended + */ + static StringBuffer toString(int mod, StringBuffer r) + { + if (isPublic(mod)) + r.append("public "); + if (isProtected(mod)) + r.append("protected "); + if (isPrivate(mod)) + r.append("private "); + if (isAbstract(mod)) + r.append("abstract "); + if (isStatic(mod)) + r.append("static "); + if (isFinal(mod)) + r.append("final "); + if (isTransient(mod)) + r.append("transient "); + if (isVolatile(mod)) + r.append("volatile "); + if (isSynchronized(mod)) + r.append("synchronized "); + if (isNative(mod)) + r.append("native "); + if (isStrict(mod)) + r.append("strictfp "); + if (isInterface(mod)) + r.append("interface "); + + // Trim trailing space. + if ((mod & ALL_FLAGS) != 0) + r.setLength(r.length() - 1); + return r; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/VMProxy.java b/gcc-4.2.1/libjava/java/lang/reflect/VMProxy.java new file mode 100644 index 000000000..b3641cf17 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/VMProxy.java @@ -0,0 +1,143 @@ +/* VMProxy.java -- VM interface for proxy class + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.lang.reflect; + +final class VMProxy +{ + /** + * Set to true if the VM provides a native method to implement + * Proxy.getProxyClass completely, including argument verification. + * If this is true, HAVE_NATIVE_GET_PROXY_DATA and + * HAVE_NATIVE_GENERATE_PROXY_CLASS should be false. + * @see java.lang.reflect.Proxy + */ + static boolean HAVE_NATIVE_GET_PROXY_CLASS = false; + + /** + * Set to true if the VM provides a native method to implement + * the first part of Proxy.getProxyClass: generation of the array + * of methods to convert, and verification of the arguments. + * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false. + * @see java.lang.reflect.Proxy + */ + static boolean HAVE_NATIVE_GET_PROXY_DATA = false; + + /** + * Set to true if the VM provides a native method to implement + * the second part of Proxy.getProxyClass: conversion of an array of + * methods into an actual proxy class. + * If this is true, HAVE_NATIVE_GET_PROXY_CLASS should be false. + * @see java.lang.reflect.Proxy + */ + static boolean HAVE_NATIVE_GENERATE_PROXY_CLASS = false; + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of getProxyClass. Only needed if + * VMProxy.HAVE_NATIVE_GET_PROXY_CLASS is true, this does the + * work of both getProxyData and generateProxyClass with no + * intermediate form in Java. The native code may safely assume that + * this class must be created, and does not already exist. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the interfaces the class will extend + * @return the generated proxy class + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see Configuration#HAVE_NATIVE_GET_PROXY_CLASS + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyData(ClassLoader, Class[]) + * @see #generateProxyClass(ProxyData) + */ + static Class getProxyClass(ClassLoader loader, Class[] interfaces) + { + return null; + } + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of getProxyData. Only needed if + * Configuration.HAVE_NATIVE_GET_PROXY_DATA is true. The native code + * may safely assume that a new ProxyData object must be created which + * does not duplicate any existing ones. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param interfaces the interfaces the class will extend + * @return all data that is required to make this proxy class + * @throws IllegalArgumentException if the constraints for getProxyClass + * were violated, except for problems with null + * @throws NullPointerException if `interfaces' is null or contains + * a null entry, or if handler is null + * @see Configuration.HAVE_NATIVE_GET_PROXY_DATA + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyClass(ClassLoader, Class[]) + * @see ProxyType#getProxyData() + */ + static Proxy.ProxyData getProxyData(ClassLoader loader, Class[] interfaces) + { + return null; + } + + /** + * Optional native method to replace (and speed up) the pure Java + * implementation of generateProxyClass. Only needed if + * Configuration.HAVE_NATIVE_GENERATE_PROXY_CLASS is true. The native + * code may safely assume that a new Class must be created, and that + * the ProxyData object does not describe any existing class. + * + * @param loader the class loader to define the proxy class in; null + * implies the bootstrap class loader + * @param data the struct of information to convert to a Class. This + * has already been verified for all problems except exceeding + * VM limitations + * @return the newly generated class + * @throws IllegalArgumentException if VM limitations are exceeded + * @see #getProxyClass(ClassLoader, Class[]) + * @see #getProxyClass(ClassLoader, Class[]) + * @see ProxyData#generateProxyClass(ClassLoader) + */ + static Class generateProxyClass(ClassLoader loader, Proxy.ProxyData data) + { + return null; + } +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/natArray.cc b/gcc-4.2.1/libjava/java/lang/reflect/natArray.cc new file mode 100644 index 000000000..b7bc8beff --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/natArray.cc @@ -0,0 +1,360 @@ +// natField.cc - Implementation of java.lang.reflect.Field native methods. + +/* Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <jvm.h> +#include <gcj/cni.h> +#include <java-stack.h> +#include <java/lang/reflect/Array.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/Byte.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> + +jobject +java::lang::reflect::Array::newInstance (jclass componentType, jint length) +{ + if (componentType->isPrimitive()) + { + // We could check for this in _Jv_NewPrimArray, but that seems + // like needless overhead when the only real route to this + // problem is here. + if (componentType == JvPrimClass (void)) + throw new java::lang::IllegalArgumentException (); + return _Jv_NewPrimArray (componentType, length); + } + else + // FIXME: class loader? + return JvNewObjectArray (length, componentType, NULL); +} + +jobject +java::lang::reflect::Array::newInstance (jclass componentType, + jintArray dimensions) +{ + jint ndims = dimensions->length; + if (ndims == 0) + throw new java::lang::IllegalArgumentException (); + jint* dims = elements (dimensions); + if (ndims == 1) + return newInstance (componentType, dims[0]); + + Class *caller = _Jv_StackTrace::GetCallingClass (&Array::class$); + ClassLoader *caller_loader = NULL; + if (caller) + caller_loader = caller->getClassLoaderInternal(); + + jclass arrayType = componentType; + for (int i = 0; i < ndims; i++) + arrayType = _Jv_GetArrayClass (arrayType, caller_loader); + + return _Jv_NewMultiArray (arrayType, ndims, dims); +} + +jint +java::lang::reflect::Array::getLength (jobject array) +{ + jclass arrayType = array->getClass(); + if (! arrayType->isArray ()) + throw new java::lang::IllegalArgumentException; + return ((__JArray*) array)->length; +} + +jclass +java::lang::reflect::Array::getElementType (jobject array, jint index) +{ + jclass arrayType = array->getClass(); + if (! arrayType->isArray ()) + throw new java::lang::IllegalArgumentException; + jint length = ((__JArray*) array)->length; + if ((_Jv_uint) index >= (_Jv_uint) length) + _Jv_ThrowBadArrayIndex(index); + return arrayType->getComponentType (); +} + +jboolean +java::lang::reflect::Array::getBoolean (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (boolean)) + return elements ((jbooleanArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jchar +java::lang::reflect::Array::getChar (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jbyte +java::lang::reflect::Array::getByte (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jshort +java::lang::reflect::Array::getShort (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jint +java::lang::reflect::Array::getInt (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jlong +java::lang::reflect::Array::getLong (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (long)) + return elements ((jlongArray) array) [index]; + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jfloat +java::lang::reflect::Array::getFloat (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (float)) + return elements ((jfloatArray) array) [index]; + if (elementType == JvPrimClass (long)) + return elements ((jlongArray) array) [index]; + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jdouble +java::lang::reflect::Array::getDouble (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (double)) + return elements ((jdoubleArray) array) [index]; + if (elementType == JvPrimClass (float)) + return elements ((jfloatArray) array) [index]; + if (elementType == JvPrimClass (long)) + return elements ((jlongArray) array) [index]; + if (elementType == JvPrimClass (int)) + return elements ((jintArray) array) [index]; + if (elementType == JvPrimClass (short)) + return elements ((jshortArray) array) [index]; + if (elementType == JvPrimClass (byte)) + return elements ((jbyteArray) array) [index]; + if (elementType == JvPrimClass (char)) + return elements ((jcharArray) array) [index]; + throw new java::lang::IllegalArgumentException; +} + +jobject +java::lang::reflect::Array::get (jobject array, jint index) +{ + jclass elementType = getElementType (array, index); + if (! elementType->isPrimitive ()) + return elements ((jobjectArray) array) [index]; + if (elementType == JvPrimClass (double)) + return new java::lang::Double (elements ((jdoubleArray) array) [index]); + if (elementType == JvPrimClass (float)) + return new java::lang::Float (elements ((jfloatArray) array) [index]); + if (elementType == JvPrimClass (long)) + return new java::lang::Long (elements ((jlongArray) array) [index]); + if (elementType == JvPrimClass (int)) + return new java::lang::Integer (elements ((jintArray) array) [index]); + if (elementType == JvPrimClass (short)) + return new java::lang::Short (elements ((jshortArray) array) [index]); + if (elementType == JvPrimClass (byte)) + return new java::lang::Byte (elements ((jbyteArray) array) [index]); + if (elementType == JvPrimClass (char)) + return new java::lang::Character (elements ((jcharArray) array) [index]); + if (elementType == JvPrimClass (boolean)) + { + _Jv_InitClass (&java::lang::Boolean::class$); + if (elements ((jbooleanArray) array) [index]) + return java::lang::Boolean::TRUE; + else + return java::lang::Boolean::FALSE; + } + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setChar (jobject array, jint index, jchar value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (char)) + elements ((jcharArray) array) [index] = value; + else if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setByte (jobject array, jint index, jbyte value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (byte)) + elements ((jbyteArray) array) [index] = value; + else if (elementType == JvPrimClass (short)) + elements ((jshortArray) array) [index] = value; + else if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setShort (jobject array, jint index, jshort value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (short)) + elements ((jshortArray) array) [index] = value; + else if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setInt (jobject array, jint index, jint value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (int)) + elements ((jintArray) array) [index] = value; + else if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setLong (jobject array, jint index, jlong value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (long)) + elements ((jlongArray) array) [index] = value; + else if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setFloat (jobject array, jint index, jfloat value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (float)) + elements ((jfloatArray) array) [index] = value; + else if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setDouble (jobject array, jint index, jdouble value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (double)) + elements ((jdoubleArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::setBoolean (jobject array, + jint index, jboolean value) +{ + jclass elementType = getElementType (array, index); + if (elementType == JvPrimClass (boolean)) + elements ((jbooleanArray) array) [index] = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Array::set (jobject array, jint index, + jobject value, jclass elType) +{ + // We don't have to call getElementType here, or check INDEX, + // because it was already done in the Java wrapper. + if (value != NULL && ! _Jv_IsInstanceOf (value, elType)) + throw new java::lang::IllegalArgumentException; + elements ((jobjectArray) array) [index] = value; +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/natConstructor.cc b/gcc-4.2.1/libjava/java/lang/reflect/natConstructor.cc new file mode 100644 index 000000000..35cf7f817 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/natConstructor.cc @@ -0,0 +1,72 @@ +// natConstructor.cc - Native code for Constructor class. + +/* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/InvocationTargetException.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/InstantiationException.h> +#include <gcj/method.h> + +jint +java::lang::reflect::Constructor::getModifiersInternal () +{ + return _Jv_FromReflectedConstructor (this)->accflags; +} + +void +java::lang::reflect::Constructor::getType () +{ + _Jv_GetTypesFromSignature (_Jv_FromReflectedConstructor (this), + declaringClass, + ¶meter_types, + NULL); + + // FIXME: for now we have no way to get exception information. + exception_types = + (JArray<jclass> *) JvNewObjectArray (0, &java::lang::Class::class$, NULL); +} + +jobject +java::lang::reflect::Constructor::newInstance (jobjectArray args) +{ + using namespace java::lang::reflect; + + if (parameter_types == NULL) + getType (); + + jmethodID meth = _Jv_FromReflectedConstructor (this); + + // Check accessibility, if required. + if (! (Modifier::isPublic (meth->accflags) || this->isAccessible())) + { + Class *caller = _Jv_StackTrace::GetCallingClass (&Constructor::class$); + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) + throw new IllegalAccessException; + } + + if (Modifier::isAbstract (declaringClass->getModifiers())) + throw new InstantiationException; + + _Jv_InitClass (declaringClass); + + // In the constructor case the return type is the type of the + // constructor. + return _Jv_CallAnyMethodA (NULL, declaringClass, meth, true, + parameter_types, args); +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/natField.cc b/gcc-4.2.1/libjava/java/lang/reflect/natField.cc new file mode 100644 index 000000000..487f62ab0 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/natField.cc @@ -0,0 +1,439 @@ +// natField.cc - Implementation of java.lang.reflect.Field native methods. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <stdlib.h> + +#include <jvm.h> +#include <java-stack.h> +#include <java/lang/reflect/Field.h> +#include <java/lang/reflect/Modifier.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/Byte.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> + +jint +java::lang::reflect::Field::getModifiersInternal () +{ + return _Jv_FromReflectedField (this)->flags; +} + +jstring +java::lang::reflect::Field::getName () +{ + if (name == NULL) + name = _Jv_NewStringUtf8Const (_Jv_FromReflectedField (this)->name); + return name; +} + +jclass +java::lang::reflect::Field::getType () +{ + if (type == NULL) + { + jfieldID fld = _Jv_FromReflectedField (this); + JvSynchronize sync (declaringClass); + _Jv_Linker::resolve_field (fld, declaringClass->getClassLoaderInternal ()); + type = fld->type; + } + return type; +} + +static void* +getAddr (java::lang::reflect::Field* field, jclass caller, jobject obj, + jboolean checkFinal) +{ + // FIXME: we know CALLER is NULL here. At one point we planned to + // have the compiler insert the caller as a hidden argument in some + // calls. However, we never implemented that, so we have to find + // the caller by hand instead. + + using namespace java::lang::reflect; + + jfieldID fld = _Jv_FromReflectedField (field); + _Jv_ushort flags = fld->getModifiers(); + + // Setting a final field is usually not allowed. + if (checkFinal + // As of 1.5, you can set a non-static final field if it is + // accessible. + && (! field->isAccessible() + || (field->getModifiers() & java::lang::reflect::Modifier::STATIC)) + && (field->getModifiers() & java::lang::reflect::Modifier::FINAL)) + throw new java::lang::IllegalAccessException(JvNewStringUTF + ("Field is final")); + + // Check accessibility, if required. + if (! (Modifier::isPublic (flags) || field->isAccessible())) + { + caller = _Jv_StackTrace::GetCallingClass (&Field::class$); + if (! _Jv_CheckAccess (caller, field->getDeclaringClass(), flags)) + throw new java::lang::IllegalAccessException; + } + + if (flags & Modifier::STATIC) + { + jclass fldClass = field->getDeclaringClass (); + JvInitClass(fldClass); + return fld->u.addr; + } + else + { + if (obj == NULL) + throw new java::lang::NullPointerException; + if (! _Jv_IsInstanceOf (obj, field->getDeclaringClass())) + throw new java::lang::IllegalArgumentException; + return (void*) ((char*) obj + fld->getOffset ()); + } +} + +static jboolean +getBoolean (jclass cls, void* addr) +{ + if (cls == JvPrimClass (boolean)) + return * (jboolean *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jchar +getChar (jclass cls, void* addr) +{ + if (cls == JvPrimClass (char)) + return * (jchar *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jbyte +getByte (jclass cls, void* addr) +{ + if (cls == JvPrimClass (byte)) + return * (jbyte *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jshort +getShort (jclass cls, void* addr) +{ + if (cls == JvPrimClass (short)) + return * (jshort *) addr; + if (cls == JvPrimClass (byte)) + return * (jbyte *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jint +getInt (jclass cls, void* addr) +{ + if (cls == JvPrimClass (int)) + return * (jint *) addr; + if (cls == JvPrimClass (short)) + return * (jshort *) addr; + if (cls == JvPrimClass (char)) + return * (jchar *) addr; + if (cls == JvPrimClass (byte)) + return * (jbyte *) addr; + throw new java::lang::IllegalArgumentException; +} + +static jlong +getLong (jclass cls, void* addr) +{ + if (cls == JvPrimClass (long)) + return * (jlong *) addr; + return ::getInt(cls, addr); +} + +static jfloat +getFloat (jclass cls, void* addr) +{ + if (cls == JvPrimClass (float)) + return * (jfloat *) addr; + if (cls == JvPrimClass (long)) + return * (jlong *) addr; + return ::getInt(cls, addr); +} + +static jdouble +getDouble (jclass cls, void* addr) +{ + if (cls == JvPrimClass (double)) + return * (jdouble *) addr; + if (cls == JvPrimClass (float)) + return * (jfloat *) addr; + if (cls == JvPrimClass (long)) + return * (jlong *) addr; + return ::getInt(cls, addr); +} + +jboolean +java::lang::reflect::Field::getBoolean (jclass caller, jobject obj) +{ + return ::getBoolean (this->getType(), getAddr (this, caller, obj, false)); +} + +jchar +java::lang::reflect::Field::getChar (jclass caller, jobject obj) +{ + return ::getChar (this->getType(), getAddr (this, caller, obj, false)); +} + +jbyte +java::lang::reflect::Field::getByte (jclass caller, jobject obj) +{ + return ::getByte (this->getType(), getAddr (this, caller, obj, false)); +} + +jshort +java::lang::reflect::Field::getShort (jclass caller, jobject obj) +{ + return ::getShort (this->getType(), getAddr (this, caller, obj, false)); +} + +jint +java::lang::reflect::Field::getInt (jclass caller, jobject obj) +{ + return ::getInt (this->getType(), getAddr (this, caller, obj, false)); +} + +jlong +java::lang::reflect::Field::getLong (jclass caller, jobject obj) +{ + return ::getLong (this->getType(), getAddr (this, caller, obj, false)); +} + +jfloat +java::lang::reflect::Field::getFloat (jclass caller, jobject obj) +{ + return ::getFloat (this->getType(), getAddr (this, caller, obj, false)); +} + +jdouble +java::lang::reflect::Field::getDouble (jclass caller, jobject obj) +{ + return ::getDouble (this->getType(), getAddr (this, caller, obj, false)); +} + +jobject +java::lang::reflect::Field::get (jclass caller, jobject obj) +{ + jclass type = this->getType(); + void* addr = getAddr (this, caller, obj, false); + if (! type->isPrimitive ()) + return * (jobject*) addr; + if (type == JvPrimClass (double)) + return new java::lang::Double (* (jdouble*) addr); + if (type == JvPrimClass (float)) + return new java::lang::Float (* (jfloat*) addr); + if (type == JvPrimClass (long)) + return new java::lang::Long (* (jlong*) addr); + if (type == JvPrimClass (int)) + return new java::lang::Integer (* (jint*) addr); + if (type == JvPrimClass (short)) + return new java::lang::Short (* (jshort*) addr); + if (type == JvPrimClass (byte)) + return new java::lang::Byte (* (jbyte*) addr); + if (type == JvPrimClass (char)) + return new java::lang::Character (* (jchar*) addr); + if (type == JvPrimClass (boolean)) + { + _Jv_InitClass (&java::lang::Boolean::class$); + if (* (jboolean*) addr) + return java::lang::Boolean::TRUE; + else + return java::lang::Boolean::FALSE; + } + throw new java::lang::IllegalArgumentException; +} + +static void +setBoolean (jclass type, void *addr, jboolean value) +{ + if (type == JvPrimClass (boolean)) + * (jboolean *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setChar (jclass type, void *addr, jchar value) +{ + if (type == JvPrimClass (char)) + * (jchar *) addr = value; + else if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setByte (jclass type, void *addr, jbyte value) +{ + if (type == JvPrimClass (byte)) + * (jbyte *) addr = value; + else if (type == JvPrimClass (short)) + * (jshort *) addr = value; + else if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setShort (jclass type, void *addr, jshort value) +{ + if (type == JvPrimClass (short)) + * (jshort *) addr = value; + else if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setInt (jclass type, void *addr, jint value) +{ + if (type == JvPrimClass (int)) + * (jint *) addr = value; + else if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setLong (jclass type, void *addr, jlong value) +{ + if (type == JvPrimClass (long)) + * (jlong *) addr = value; + else if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setFloat (jclass type, void *addr, jfloat value) +{ + if (type == JvPrimClass (float)) + * (jfloat *) addr = value; + else if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +static void +setDouble (jclass type, void *addr, jdouble value) +{ + if (type == JvPrimClass (double)) + * (jdouble *) addr = value; + else + throw new java::lang::IllegalArgumentException; +} + +void +java::lang::reflect::Field::setBoolean (jclass caller, jobject obj, jboolean b, + jboolean checkFinal) +{ + ::setBoolean (this->getType(), getAddr (this, caller, obj, checkFinal), b); +} + +void +java::lang::reflect::Field::setChar (jclass caller, jobject obj, jchar c, + jboolean checkFinal) +{ + ::setChar (this->getType(), getAddr (this, caller, obj, checkFinal), c); +} + +void +java::lang::reflect::Field::setByte (jclass caller, jobject obj, jbyte b, + jboolean checkFinal) +{ + ::setByte (this->getType(), getAddr (this, caller, obj, checkFinal), b); +} + +void +java::lang::reflect::Field::setShort (jclass caller, jobject obj, jshort s, + jboolean checkFinal) +{ + ::setShort (this->getType(), getAddr (this, caller, obj, checkFinal), s); +} + +void +java::lang::reflect::Field::setInt (jclass caller, jobject obj, jint i, + jboolean checkFinal) +{ + ::setInt (this->getType(), getAddr (this, caller, obj, checkFinal), i); +} + +void +java::lang::reflect::Field::setLong (jclass caller, jobject obj, jlong l, + jboolean checkFinal) +{ + ::setLong (this->getType(), getAddr (this, caller, obj, checkFinal), l); +} + +void +java::lang::reflect::Field::setFloat (jclass caller, jobject obj, jfloat f, + jboolean checkFinal) +{ + ::setFloat (this->getType(), getAddr (this, caller, obj, checkFinal), f); +} + +void +java::lang::reflect::Field::setDouble (jclass caller, jobject obj, jdouble d, + jboolean checkFinal) +{ + ::setDouble (this->getType(), getAddr (this, caller, obj, checkFinal), d); +} + +void +java::lang::reflect::Field::set (jclass caller, jobject object, jobject value, + jclass type, jboolean checkFinal) +{ + void* addr = getAddr (this, caller, object, checkFinal); + if (value != NULL && ! _Jv_IsInstanceOf (value, type)) + throw new java::lang::IllegalArgumentException; + * (jobject*) addr = value; +} diff --git a/gcc-4.2.1/libjava/java/lang/reflect/natMethod.cc b/gcc-4.2.1/libjava/java/lang/reflect/natMethod.cc new file mode 100644 index 000000000..eb7170a02 --- /dev/null +++ b/gcc-4.2.1/libjava/java/lang/reflect/natMethod.cc @@ -0,0 +1,654 @@ +// natMethod.cc - Native code for Method class. + +/* Copyright (C) 1998, 1999, 2000, 2001 , 2002, 2003, 2004, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <jni.h> +#include <java-stack.h> + +#include <java/lang/reflect/Method.h> +#include <java/lang/reflect/Constructor.h> +#include <java/lang/reflect/InvocationTargetException.h> +#include <java/lang/reflect/Modifier.h> + +#include <java/lang/Void.h> +#include <java/lang/Byte.h> +#include <java/lang/Boolean.h> +#include <java/lang/Character.h> +#include <java/lang/Short.h> +#include <java/lang/Integer.h> +#include <java/lang/Long.h> +#include <java/lang/Float.h> +#include <java/lang/Double.h> +#include <java/lang/IllegalAccessException.h> +#include <java/lang/IllegalArgumentException.h> +#include <java/lang/IncompatibleClassChangeError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/VirtualMachineError.h> +#include <java/lang/Class.h> +#include <gcj/method.h> +#include <gnu/gcj/RawData.h> +#include <java/lang/NoClassDefFoundError.h> + +#include <stdlib.h> + +#if USE_LIBFFI +#include <ffi.h> +#else +#include <java/lang/UnsupportedOperationException.h> +#endif + +struct cpair +{ + jclass prim; + jclass wrap; +}; + +// This is used to determine when a primitive widening conversion is +// allowed. +static cpair primitives[] = +{ +#define BOOLEAN 0 + { JvPrimClass (boolean), &java::lang::Boolean::class$ }, + { JvPrimClass (byte), &java::lang::Byte::class$ }, +#define SHORT 2 + { JvPrimClass (short), &java::lang::Short::class$ }, +#define CHAR 3 + { JvPrimClass (char), &java::lang::Character::class$ }, + { JvPrimClass (int), &java::lang::Integer::class$ }, + { JvPrimClass (long), &java::lang::Long::class$ }, + { JvPrimClass (float), &java::lang::Float::class$ }, + { JvPrimClass (double), &java::lang::Double::class$ }, + { NULL, NULL } +}; + +static inline jboolean +can_widen (jclass from, jclass to) +{ + int fromx = -1, tox = -1; + + for (int i = 0; primitives[i].prim; ++i) + { + if (primitives[i].wrap == from) + fromx = i; + if (primitives[i].prim == to) + tox = i; + } + + // Can't handle a miss. + if (fromx == -1 || tox == -1) + return false; + // Boolean arguments may not be widened. + if (fromx == BOOLEAN && tox != BOOLEAN) + return false; + // Nothing promotes to char. + if (tox == CHAR && fromx != CHAR) + return false; + + return fromx <= tox; +} + +#ifdef USE_LIBFFI +static inline ffi_type * +get_ffi_type (jclass klass) +{ + // A special case. + if (klass == NULL) + return &ffi_type_pointer; + + ffi_type *r; + if (klass == JvPrimClass (byte)) + r = &ffi_type_sint8; + else if (klass == JvPrimClass (short)) + r = &ffi_type_sint16; + else if (klass == JvPrimClass (int)) + r = &ffi_type_sint32; + else if (klass == JvPrimClass (long)) + r = &ffi_type_sint64; + else if (klass == JvPrimClass (float)) + r = &ffi_type_float; + else if (klass == JvPrimClass (double)) + r = &ffi_type_double; + else if (klass == JvPrimClass (boolean)) + { + // On some platforms a bool is a byte, on others an int. + if (sizeof (jboolean) == sizeof (jbyte)) + r = &ffi_type_sint8; + else + { + JvAssert (sizeof (jboolean) == sizeof (jint)); + r = &ffi_type_sint32; + } + } + else if (klass == JvPrimClass (char)) + r = &ffi_type_uint16; + else + { + JvAssert (! klass->isPrimitive()); + r = &ffi_type_pointer; + } + + return r; +} +#endif // USE_LIBFFI + +jobject +java::lang::reflect::Method::invoke (jobject obj, jobjectArray args) +{ + using namespace java::lang::reflect; + jclass iface = NULL; + + if (parameter_types == NULL) + getType (); + + jmethodID meth = _Jv_FromReflectedMethod (this); + + if (Modifier::isStatic(meth->accflags)) + { + // We have to initialize a static class. It is safe to do this + // here and not in _Jv_CallAnyMethodA because JNI initializes a + // class whenever a method lookup is done. + _Jv_InitClass (declaringClass); + } + else + { + jclass objClass = JV_CLASS (obj); + if (! _Jv_IsAssignableFrom (objClass, declaringClass)) + throw new java::lang::IllegalArgumentException; + } + + // Check accessibility, if required. + if (! (Modifier::isPublic (meth->accflags) || this->isAccessible())) + { + Class *caller = _Jv_StackTrace::GetCallingClass (&Method::class$); + if (! _Jv_CheckAccess(caller, declaringClass, meth->accflags)) + throw new IllegalAccessException; + } + + if (declaringClass->isInterface()) + iface = declaringClass; + + return _Jv_CallAnyMethodA (obj, return_type, meth, false, + parameter_types, args, iface); +} + +jint +java::lang::reflect::Method::getModifiersInternal () +{ + return _Jv_FromReflectedMethod (this)->accflags; +} + +jstring +java::lang::reflect::Method::getName () +{ + if (name == NULL) + name = _Jv_NewStringUtf8Const (_Jv_FromReflectedMethod (this)->name); + return name; +} + +/* Internal method to set return_type and parameter_types fields. */ + +void +java::lang::reflect::Method::getType () +{ + _Jv_Method *method = _Jv_FromReflectedMethod (this); + _Jv_GetTypesFromSignature (method, + declaringClass, + ¶meter_types, + &return_type); + + int count = 0; + if (method->throws != NULL) + { + while (method->throws[count] != NULL) + ++count; + } + + exception_types + = (JArray<jclass> *) JvNewObjectArray (count, &java::lang::Class::class$, + NULL); + jclass *elts = elements (exception_types); + for (int i = 0; i < count; ++i) + elts[i] = _Jv_FindClass (method->throws[i], + declaringClass->getClassLoaderInternal ()); +} + +void +_Jv_GetTypesFromSignature (jmethodID method, + jclass declaringClass, + JArray<jclass> **arg_types_out, + jclass *return_type_out) +{ + + _Jv_Utf8Const* sig = method->signature; + java::lang::ClassLoader *loader = declaringClass->getClassLoaderInternal(); + char *ptr = sig->chars(); + int numArgs = 0; + /* First just count the number of parameters. */ + // FIXME: should do some validation here, e.g., that there is only + // one return type. + for (; ; ptr++) + { + switch (*ptr) + { + case 0: + case ')': + case 'V': + break; + case '[': + case '(': + continue; + case 'B': + case 'C': + case 'D': + case 'F': + case 'S': + case 'I': + case 'J': + case 'Z': + numArgs++; + continue; + case 'L': + numArgs++; + do + ptr++; + while (*ptr != ';' && ptr[1] != '\0'); + continue; + } + break; + } + + JArray<jclass> *args = (JArray<jclass> *) + JvNewObjectArray (numArgs, &java::lang::Class::class$, NULL); + jclass* argPtr = elements (args); + for (ptr = sig->chars(); *ptr != '\0'; ptr++) + { + if (*ptr == '(') + continue; + if (*ptr == ')') + { + argPtr = return_type_out; + continue; + } + + char *end_ptr; + jclass type = _Jv_FindClassFromSignature (ptr, loader, &end_ptr); + if (type == NULL) + // FIXME: This isn't ideal. + throw new java::lang::NoClassDefFoundError (sig->toString()); + + // ARGPTR can be NULL if we are processing the return value of a + // call from Constructor. + if (argPtr) + *argPtr++ = type; + + ptr = end_ptr; + } + *arg_types_out = args; +} + +// This is a very rough analog of the JNI CallNonvirtual<type>MethodA +// functions. It handles both Methods and Constructors, and it can +// handle any return type. In the Constructor case, the `obj' +// argument is unused and should be NULL; also, the `return_type' is +// the class that the constructor will construct. RESULT is a pointer +// to a `jvalue' (see jni.h); for a void method this should be NULL. +// This function returns an exception (if one was thrown), or NULL if +// the call went ok. +void +_Jv_CallAnyMethodA (jobject obj, + jclass return_type, + jmethodID meth, + jboolean is_constructor, + jboolean is_virtual_call, + JArray<jclass> *parameter_types, + jvalue *args, + jvalue *result, + jboolean is_jni_call, + jclass iface) +{ + using namespace java::lang::reflect; + +#ifdef USE_LIBFFI + JvAssert (! is_constructor || ! obj); + JvAssert (! is_constructor || return_type); + + // See whether call needs an object as the first argument. A + // constructor does need a `this' argument, but it is one we create. + jboolean needs_this = false; + if (is_constructor + || ! Modifier::isStatic(meth->accflags)) + needs_this = true; + + int param_count = parameter_types->length; + if (needs_this) + ++param_count; + + ffi_type *rtype; + // A constructor itself always returns void. + if (is_constructor || return_type == JvPrimClass (void)) + rtype = &ffi_type_void; + else + rtype = get_ffi_type (return_type); + ffi_type **argtypes = (ffi_type **) __builtin_alloca (param_count + * sizeof (ffi_type *)); + + jclass *paramelts = elements (parameter_types); + + // Special case for the `this' argument of a constructor. Note that + // the JDK 1.2 docs specify that the new object must be allocated + // before argument conversions are done. + if (is_constructor) + obj = _Jv_AllocObject (return_type); + + const int size_per_arg = sizeof(jvalue); + ffi_cif cif; + + char *p = (char *) __builtin_alloca (param_count * size_per_arg); + // Overallocate to get correct alignment. + void **values = (void **) + __builtin_alloca (param_count * sizeof (void *)); + + int i = 0; + if (needs_this) + { + // The `NULL' type is `Object'. + argtypes[i] = get_ffi_type (NULL); + values[i] = p; + memcpy (p, &obj, sizeof (jobject)); + p += size_per_arg; + ++i; + } + + for (int arg = 0; i < param_count; ++i, ++arg) + { + int tsize; + + argtypes[i] = get_ffi_type (paramelts[arg]); + if (paramelts[arg]->isPrimitive()) + tsize = paramelts[arg]->size(); + else + tsize = sizeof (jobject); + + // Copy appropriate bits from the jvalue into the ffi array. + // FIXME: we could do this copying all in one loop, above, by + // over-allocating a bit. + // How do we do this without breaking big-endian platforms? + values[i] = p; + memcpy (p, &args[arg], tsize); + p += size_per_arg; + } + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, param_count, + rtype, argtypes) != FFI_OK) + throw new java::lang::VirtualMachineError(JvNewStringLatin1("internal error: ffi_prep_cif failed")); + + using namespace java::lang; + using namespace java::lang::reflect; + + union + { + ffi_arg i; + jobject o; + jlong l; + jfloat f; + jdouble d; + } ffi_result; + + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = 0; + break; + case FFI_TYPE_SINT16: + result->s = 0; + break; + case FFI_TYPE_UINT16: + result->c = 0; + break; + case FFI_TYPE_SINT32: + result->i = 0; + break; + case FFI_TYPE_SINT64: + result->j = 0; + break; + case FFI_TYPE_FLOAT: + result->f = 0; + break; + case FFI_TYPE_DOUBLE: + result->d = 0; + break; + case FFI_TYPE_POINTER: + result->l = 0; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + + void *ncode; + + // FIXME: If a vtable index is -1 at this point it is invalid, so we + // have to use the ncode. + // + // This can happen because methods in final classes don't have + // vtable entries, but _Jv_isVirtualMethod() doesn't know that. We + // could solve this problem by allocating a vtable index for methods + // in final classes. + if (is_virtual_call + && ! Modifier::isFinal (meth->accflags) + && (_Jv_ushort)-1 != meth->index) + { + _Jv_VTable *vtable = *(_Jv_VTable **) obj; + if (iface == NULL) + { + if (is_jni_call && Modifier::isAbstract (meth->accflags)) + { + // With JNI we don't know if this is an interface call + // or a call to an abstract method. Look up the method + // by name, the slow way. + _Jv_Method *concrete_meth + = _Jv_LookupDeclaredMethod (vtable->clas, + meth->name, + meth->signature, + NULL); + if (concrete_meth == NULL + || concrete_meth->ncode == NULL + || Modifier::isAbstract(concrete_meth->accflags)) + throw new java::lang::IncompatibleClassChangeError + (_Jv_GetMethodString (vtable->clas, meth)); + ncode = concrete_meth->ncode; + } + else + ncode = vtable->get_method (meth->index); + } + else + ncode = _Jv_LookupInterfaceMethodIdx (vtable->clas, iface, + meth->index); + } + else + { + ncode = meth->ncode; + } + + try + { + ffi_call (&cif, (void (*)()) ncode, &ffi_result, values); + } + catch (Throwable *ex) + { + // For JNI we just throw the real error. For reflection, we + // wrap the underlying method's exception in an + // InvocationTargetException. + if (! is_jni_call) + ex = new InvocationTargetException (ex); + throw ex; + } + + // Since ffi_call returns integer values promoted to a word, use + // a narrowing conversion for jbyte, jchar, etc. results. + // Note that boolean is handled either by the FFI_TYPE_SINT8 or + // FFI_TYPE_SINT32 case. + if (is_constructor) + result->l = obj; + else + { + switch (rtype->type) + { + case FFI_TYPE_VOID: + break; + case FFI_TYPE_SINT8: + result->b = (jbyte)ffi_result.i; + break; + case FFI_TYPE_SINT16: + result->s = (jshort)ffi_result.i; + break; + case FFI_TYPE_UINT16: + result->c = (jchar)ffi_result.i; + break; + case FFI_TYPE_SINT32: + result->i = (jint)ffi_result.i; + break; + case FFI_TYPE_SINT64: + result->j = (jlong)ffi_result.l; + break; + case FFI_TYPE_FLOAT: + result->f = (jfloat)ffi_result.f; + break; + case FFI_TYPE_DOUBLE: + result->d = (jdouble)ffi_result.d; + break; + case FFI_TYPE_POINTER: + result->l = (jobject)ffi_result.o; + break; + default: + JvFail ("Unknown ffi_call return type"); + break; + } + } +#else + throw new java::lang::UnsupportedOperationException(JvNewStringLatin1("reflection not available in this build")); +#endif // USE_LIBFFI +} + +// This is another version of _Jv_CallAnyMethodA, but this one does +// more checking and is used by the reflection (and not JNI) code. +jobject +_Jv_CallAnyMethodA (jobject obj, + jclass return_type, + jmethodID meth, + jboolean is_constructor, + JArray<jclass> *parameter_types, + jobjectArray args, + jclass iface) +{ + if (parameter_types->length == 0 && args == NULL) + { + // The JDK accepts this, so we do too. + } + else if (parameter_types->length != args->length) + throw new java::lang::IllegalArgumentException; + + int param_count = parameter_types->length; + + jclass *paramelts = elements (parameter_types); + jobject *argelts = args == NULL ? NULL : elements (args); + jvalue argvals[param_count]; + +#define COPY(Where, What, Type) \ + do { \ + Type val = (What); \ + memcpy ((Where), &val, sizeof (Type)); \ + } while (0) + + for (int i = 0; i < param_count; ++i) + { + jclass k = argelts[i] ? argelts[i]->getClass() : NULL; + if (paramelts[i]->isPrimitive()) + { + if (! argelts[i] + || ! k + || ! can_widen (k, paramelts[i])) + throw new java::lang::IllegalArgumentException; + + if (paramelts[i] == JvPrimClass (boolean)) + COPY (&argvals[i], + ((java::lang::Boolean *) argelts[i])->booleanValue(), + jboolean); + else if (paramelts[i] == JvPrimClass (char)) + COPY (&argvals[i], + ((java::lang::Character *) argelts[i])->charValue(), + jchar); + else + { + java::lang::Number *num = (java::lang::Number *) argelts[i]; + if (paramelts[i] == JvPrimClass (byte)) + COPY (&argvals[i], num->byteValue(), jbyte); + else if (paramelts[i] == JvPrimClass (short)) + COPY (&argvals[i], num->shortValue(), jshort); + else if (paramelts[i] == JvPrimClass (int)) + COPY (&argvals[i], num->intValue(), jint); + else if (paramelts[i] == JvPrimClass (long)) + COPY (&argvals[i], num->longValue(), jlong); + else if (paramelts[i] == JvPrimClass (float)) + COPY (&argvals[i], num->floatValue(), jfloat); + else if (paramelts[i] == JvPrimClass (double)) + COPY (&argvals[i], num->doubleValue(), jdouble); + } + } + else + { + if (argelts[i] && ! paramelts[i]->isAssignableFrom (k)) + throw new java::lang::IllegalArgumentException; + COPY (&argvals[i], argelts[i], jobject); + } + } + + jvalue ret_value; + _Jv_CallAnyMethodA (obj, return_type, meth, is_constructor, + _Jv_isVirtualMethod (meth), + parameter_types, argvals, &ret_value, + false, iface); + + jobject r; +#define VAL(Wrapper, Field) (new Wrapper (ret_value.Field)) + if (is_constructor) + r = ret_value.l; + else if (return_type == JvPrimClass (byte)) + r = VAL (java::lang::Byte, b); + else if (return_type == JvPrimClass (short)) + r = VAL (java::lang::Short, s); + else if (return_type == JvPrimClass (int)) + r = VAL (java::lang::Integer, i); + else if (return_type == JvPrimClass (long)) + r = VAL (java::lang::Long, j); + else if (return_type == JvPrimClass (float)) + r = VAL (java::lang::Float, f); + else if (return_type == JvPrimClass (double)) + r = VAL (java::lang::Double, d); + else if (return_type == JvPrimClass (boolean)) + r = VAL (java::lang::Boolean, z); + else if (return_type == JvPrimClass (char)) + r = VAL (java::lang::Character, c); + else if (return_type == JvPrimClass (void)) + r = NULL; + else + { + JvAssert (return_type == NULL || ! return_type->isPrimitive()); + r = ret_value.l; + } + + return r; +} diff --git a/gcc-4.2.1/libjava/java/net/InetAddress.java b/gcc-4.2.1/libjava/java/net/InetAddress.java new file mode 100644 index 000000000..640750d63 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/InetAddress.java @@ -0,0 +1,819 @@ +/* InetAddress.java -- Class to model an Internet address + Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.net; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamException; +import java.io.Serializable; + +/** + * This class models an Internet address. It does not have a public + * constructor. Instead, new instances of this objects are created + * using the static methods getLocalHost(), getByName(), and + * getAllByName(). + * + * <p>This class fulfills the function of the C style functions gethostname(), + * gethostbyname(), and gethostbyaddr(). It resolves Internet DNS names + * into their corresponding numeric addresses and vice versa.</p> + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Per Bothner + * @author Gary Benson (gbenson@redhat.com) + * + * @specnote This class is not final since JK 1.4 + */ +public class InetAddress implements Serializable +{ + private static final long serialVersionUID = 3286316764910316507L; + + /** + * Stores static localhost address object. + */ + static InetAddress LOCALHOST; + static + { + try + { + LOCALHOST = getByAddress("localhost", new byte[] {127, 0, 0, 1}); + // Some soon-to-be-removed native code synchronizes on this. + loopbackAddress = LOCALHOST; + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Dummy InetAddress, used to bind socket to any (all) network interfaces. + */ + static InetAddress ANY_IF; + static + { + byte[] addr; + try + { + addr = VMInetAddress.lookupInaddrAny(); + } + catch (UnknownHostException e) + { + // Make one up and hope it works. + addr = new byte[] {0, 0, 0, 0}; + } + try + { + ANY_IF = getByAddress(addr); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + ANY_IF.hostName = ANY_IF.getHostName(); + } + + /** + * The Serialized Form specifies that an int 'address' is saved/restored. + * This class uses a byte array internally so we'll just do the conversion + * at serialization time and leave the rest of the algorithm as is. + */ + private int address; + + /** + * An array of octets representing an IP address. + */ + transient byte[] addr; + + /** + * The name of the host for this address. + */ + String hostName; + + /** + * Needed for serialization. + */ + private int family; + + /** + * Constructor. Prior to the introduction of IPv6 support in 1.4, + * methods such as InetAddress.getByName() would return InetAddress + * objects. From 1.4 such methods returned either Inet4Address or + * Inet6Address objects, but for compatibility Inet4Address objects + * are serialized as InetAddresses. As such, there are only two + * places where it is appropriate to invoke this constructor: within + * subclasses constructors and within Inet4Address.writeReplace(). + * + * @param ipaddr The IP number of this address as an array of bytes + * @param hostname The hostname of this IP address. + * @param family The address family of this IP address. + */ + InetAddress(byte[] ipaddr, String hostname, int family) + { + addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone(); + hostName = hostname; + this.family = family; + } + + /** + * Returns true if this address is a multicast address, false otherwise. + * An address is multicast if the high four bits are "1110". These are + * also known as "Class D" addresses. + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @return true if mulitcast, false if not + * + * @since 1.1 + */ + public boolean isMulticastAddress() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isMulticastAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if the InetAddress in a wildcard address + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isAnyLocalAddress() + { + // This is inefficient, but certain methods on Win32 create + // InetAddress objects using "new InetAddress" rather than + // "InetAddress.getByAddress" so we provide a method body. + // This code is never executed on Posix systems. + try + { + return getByAddress(hostName, addr).isAnyLocalAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if the InetAddress is a loopback address + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isLoopbackAddress() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isLoopbackAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a link local address + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isLinkLocalAddress() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isLinkLocalAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a site local address + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isSiteLocalAddress() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isSiteLocalAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a global multicast address + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isMCGlobal() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isMCGlobal(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a node local multicast address. + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isMCNodeLocal() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isMCNodeLocal(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a link local multicast address. + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isMCLinkLocal() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isMCLinkLocal(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a site local multicast address. + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isMCSiteLocal() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isMCSiteLocal(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Utility routine to check if InetAddress is a organization local + * multicast address. + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @since 1.4 + */ + public boolean isMCOrgLocal() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).isMCOrgLocal(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Returns the hostname for this address. This will return the IP address + * as a String if there is no hostname available for this address + * + * @return The hostname for this address + */ + public String getHostName() + { + if (hostName == null) + hostName = getCanonicalHostName(); + + return hostName; + } + + /** + * Returns the canonical hostname represented by this InetAddress + */ + String internalGetCanonicalHostName() + { + try + { + return ResolverCache.getHostByAddr(addr); + } + catch (UnknownHostException e) + { + return getHostAddress(); + } + } + + /** + * Returns the canonical hostname represented by this InetAddress + * + * @since 1.4 + */ + public String getCanonicalHostName() + { + String hostname = internalGetCanonicalHostName(); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + { + try + { + sm.checkConnect(hostname, -1); + } + catch (SecurityException e) + { + return getHostAddress(); + } + } + + return hostname; + } + + /** + * Returns the IP address of this object as a byte array. + * + * @return IP address + */ + public byte[] getAddress() + { + // An experiment shows that JDK1.2 returns a different byte array each + // time. This makes sense, in terms of security. + return (byte[]) addr.clone(); + } + + /** + * Returns the IP address of this object as a String. + * + * <p>This method cannot be abstract for backward compatibility reasons. By + * default it always throws {@link UnsupportedOperationException} unless + * overridden.</p> + * + * @return The IP address of this object in String form + * + * @since 1.0.2 + */ + public String getHostAddress() + { + // This method is masked on Posix systems, where all InetAddress + // objects are created using InetAddress.getByAddress() which + // returns either Inet4Address or Inet6Address objects. Certain + // native methods on Win32 use "new InetAddress" in which case + // this method will be visible. + try + { + return getByAddress(hostName, addr).getHostAddress(); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Returns a hash value for this address. Useful for creating hash + * tables. Overrides Object.hashCode() + * + * @return A hash value for this address. + */ + public int hashCode() + { + // There hashing algorithm is not specified, but a simple experiment + // shows that it is equal to the address, as a 32-bit big-endian integer. + int hash = 0; + int len = addr.length; + int i = len > 4 ? len - 4 : 0; + + for (; i < len; i++) + hash = (hash << 8) | (addr[i] & 0xff); + + return hash; + } + + /** + * Tests this address for equality against another InetAddress. The two + * addresses are considered equal if they contain the exact same octets. + * This implementation overrides Object.equals() + * + * @param obj The address to test for equality + * + * @return true if the passed in object's address is equal to this one's, + * false otherwise + */ + public boolean equals(Object obj) + { + if (! (obj instanceof InetAddress)) + return false; + + // "The Java Class Libraries" 2nd edition says "If a machine has + // multiple names instances of InetAddress for different name of + // that same machine are not equal. This is because they have + // different host names." This violates the description in the + // JDK 1.2 API documentation. A little experimentation + // shows that the latter is correct. + byte[] addr2 = ((InetAddress) obj).addr; + + if (addr.length != addr2.length) + return false; + + for (int i = 0; i < addr.length; i++) + if (addr[i] != addr2[i]) + return false; + + return true; + } + + /** + * Converts this address to a String. This string contains the IP in + * dotted decimal form. For example: "127.0.0.1" This method is equivalent + * to getHostAddress() and overrides Object.toString() + * + * @return This address in String form + */ + public String toString() + { + String addr = getHostAddress(); + String host = (hostName != null) ? hostName : ""; + return host + "/" + addr; + } + + /** + * Returns an InetAddress object given the raw IP address. + * + * The argument is in network byte order: the highest order byte of the + * address is in getAddress()[0]. + * + * @param addr The IP address to create the InetAddress object from + * + * @exception UnknownHostException If IP address has illegal length + * + * @since 1.4 + */ + public static InetAddress getByAddress(byte[] addr) + throws UnknownHostException + { + return getByAddress(null, addr); + } + + /** + * Creates an InetAddress based on the provided host name and IP address. + * No name service is checked for the validity of the address. + * + * @param host The hostname of the InetAddress object to create + * @param addr The IP address to create the InetAddress object from + * + * @exception UnknownHostException If IP address is of illegal length + * + * @since 1.4 + */ + public static InetAddress getByAddress(String host, byte[] addr) + throws UnknownHostException + { + if (addr.length == 4) + return new Inet4Address(addr, host); + + if (addr.length == 16) + { + for (int i = 0; i < 12; i++) + { + if (addr[i] != (i < 10 ? 0 : (byte) 0xFF)) + return new Inet6Address(addr, host); + } + + byte[] ip4addr = new byte[4]; + ip4addr[0] = addr[12]; + ip4addr[1] = addr[13]; + ip4addr[2] = addr[14]; + ip4addr[3] = addr[15]; + return new Inet4Address(ip4addr, host); + } + + throw new UnknownHostException("IP address has illegal length"); + } + + /** + * Returns an InetAddress object representing the IP address of + * the given literal IP address in dotted decimal format such as + * "127.0.0.1". This is used by SocketPermission.setHostPort() + * to parse literal IP addresses without performing a DNS lookup. + * + * @param literal The literal IP address to create the InetAddress + * object from + * + * @return The address of the host as an InetAddress object, or + * null if the IP address is invalid. + */ + static InetAddress getByLiteral(String literal) + { + byte[] address = VMInetAddress.aton(literal); + if (address == null) + return null; + + try + { + return getByAddress(address); + } + catch (UnknownHostException e) + { + throw new RuntimeException("should never happen", e); + } + } + + /** + * Returns an InetAddress object representing the IP address of the given + * hostname. This name can be either a hostname such as "www.urbanophile.com" + * or an IP address in dotted decimal format such as "127.0.0.1". If the + * hostname is null or "", the hostname of the local machine is supplied by + * default. This method is equivalent to returning the first element in + * the InetAddress array returned from GetAllByName. + * + * @param hostname The name of the desired host, or null for the local + * loopback address. + * + * @return The address of the host as an InetAddress object. + * + * @exception UnknownHostException If no IP address for the host could + * be found + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + public static InetAddress getByName(String hostname) + throws UnknownHostException + { + InetAddress[] addresses = getAllByName(hostname); + return addresses[0]; + } + + /** + * Returns an array of InetAddress objects representing all the host/ip + * addresses of a given host, given the host's name. This name can be + * either a hostname such as "www.urbanophile.com" or an IP address in + * dotted decimal format such as "127.0.0.1". If the value is null, the + * hostname of the local machine is supplied by default. + * + * @param hostname The name of the desired host, or null for the + * local loopback address. + * + * @return All addresses of the host as an array of InetAddress objects. + * + * @exception UnknownHostException If no IP address for the host could + * be found + * @exception SecurityException If a security manager exists and its + * checkConnect method doesn't allow the operation + */ + public static InetAddress[] getAllByName(String hostname) + throws UnknownHostException + { + // If null or the empty string is supplied, the loopback address + // is returned. + if (hostname == null || hostname.length() == 0) + return new InetAddress[] {LOCALHOST}; + + // Check if hostname is an IP address + InetAddress address = getByLiteral(hostname); + if (address != null) + return new InetAddress[] {address}; + + // Perform security check before resolving + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkConnect(hostname, -1); + + // Resolve the hostname + byte[][] iplist = ResolverCache.getHostByName(hostname); + if (iplist.length == 0) + throw new UnknownHostException(hostname); + + InetAddress[] addresses = new InetAddress[iplist.length]; + for (int i = 0; i < iplist.length; i++) + addresses[i] = getByAddress(hostname, iplist[i]); + + return addresses; + } + + /** + * Returns an InetAddress object representing the address of the current + * host. + * + * @return The local host's address + * + * @exception UnknownHostException If no IP address for the host could + * be found + */ + public static InetAddress getLocalHost() throws UnknownHostException + { + String hostname = VMInetAddress.getLocalHostname(); + try + { + return getByName(hostname); + } + catch (SecurityException e) + { + return LOCALHOST; + } + } + + /** + * Inet4Address objects are serialized as InetAddress objects. + * This deserializes them back into Inet4Address objects. + */ + private Object readResolve() throws ObjectStreamException + { + return new Inet4Address(addr, hostName); + } + + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + ois.defaultReadObject(); + addr = new byte[4]; + addr[3] = (byte) address; + + for (int i = 2; i >= 0; --i) + addr[i] = (byte) (address >>= 8); + } + + private void writeObject(ObjectOutputStream oos) throws IOException + { + // Build a 32 bit address from the last 4 bytes of a 4 byte IPv4 address + // or a 16 byte IPv6 address. + int len = addr.length; + int i = len - 4; + + for (; i < len; i++) + address = address << 8 | (addr[i] & 0xff); + + oos.defaultWriteObject(); + } + + // The native methods remain here for now; + // methods in VMInetAddress map onto them. + static native byte[] aton(String hostname); + static native InetAddress[] lookup (String hostname, + InetAddress ipaddr, boolean all); + static native int getFamily (byte[] ipaddr); + static native String getLocalHostname(); + + // Some soon-to-be-removed native code synchronizes on this. + static InetAddress loopbackAddress; + + // Some soon-to-be-removed code uses this old and broken method. + InetAddress(byte[] ipaddr, String hostname) + { + addr = (null == ipaddr) ? null : (byte[]) ipaddr.clone(); + hostName = hostname; + + if (ipaddr != null) + family = getFamily(ipaddr); + } + + // Some soon-to-be-removed native code uses these old methods. + private static InetAddress[] allocArray (int count) + { + return new InetAddress [count]; + } + private static SecurityException checkConnect (String hostname) + { + return null; + } +} diff --git a/gcc-4.2.1/libjava/java/net/URL.java b/gcc-4.2.1/libjava/java/net/URL.java new file mode 100644 index 000000000..0ae7c1cfb --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/URL.java @@ -0,0 +1,974 @@ +/* URL.java -- Uniform Resource Locator Class + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.net; + +import gnu.java.net.URLParseError; + +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.StringTokenizer; + + +/* + * Written using on-line Java Platform 1.2 API Specification, as well + * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998). + * Status: Believed complete and correct. + */ + +/** + * This final class represents an Internet Uniform Resource Locator (URL). + * For details on the syntax of URL's and what they can be used for, + * refer to RFC 1738, available from <a + * href="http://ds.internic.net/rfcs/rfc1738.txt"> + * http://ds.internic.net/rfcs/rfc1738.txt</a> + * <p> + * There are a great many protocols supported by URL's such as "http", + * "ftp", and "file". This object can handle any arbitrary URL for which + * a URLStreamHandler object can be written. Default protocol handlers + * are provided for the "http" and "ftp" protocols. Additional protocols + * handler implementations may be provided in the future. In any case, + * an application or applet can install its own protocol handlers that + * can be "chained" with other protocol hanlders in the system to extend + * the base functionality provided with this class. (Note, however, that + * unsigned applets cannot access properties by default or install their + * own protocol handlers). + * <p> + * This chaining is done via the system property java.protocol.handler.pkgs + * If this property is set, it is assumed to be a "|" separated list of + * package names in which to attempt locating protocol handlers. The + * protocol handler is searched for by appending the string + * ".<protocol>.Handler" to each packed in the list until a hander is + * found. If a protocol handler is not found in this list of packages, or if + * the property does not exist, then the default protocol handler of + * "gnu.java.net.<protocol>.Handler" is tried. If this is + * unsuccessful, a MalformedURLException is thrown. + * <p> + * All of the constructor methods of URL attempt to load a protocol + * handler and so any needed protocol handlers must be installed when + * the URL is constructed. + * <p> + * Here is an example of how URL searches for protocol handlers. Assume + * the value of java.protocol.handler.pkgs is "com.foo|com.bar" and the + * URL is "news://comp.lang.java.programmer". URL would looking the + * following places for protocol handlers: + * <p><pre> + * com.foo.news.Handler + * com.bar.news.Handler + * gnu.java.net.news.Handler + * </pre><p> + * If the protocol handler is not found in any of those locations, a + * MalformedURLException would be thrown. + * <p> + * Please note that a protocol handler must be a subclass of + * URLStreamHandler. + * <p> + * Normally, this class caches protocol handlers. Once it finds a handler + * for a particular protocol, it never tries to look up a new handler + * again. However, if the system property + * gnu.java.net.nocache_protocol_handlers is set, then this + * caching behavior is disabled. This property is specific to this + * implementation. Sun's JDK may or may not do protocol caching, but it + * almost certainly does not examine this property. + * <p> + * Please also note that an application can install its own factory for + * loading protocol handlers (see setURLStreamHandlerFactory). If this is + * done, then the above information is superseded and the behavior of this + * class in loading protocol handlers is dependent on that factory. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + * + * @see URLStreamHandler + */ +public final class URL implements Serializable +{ + private static final String DEFAULT_SEARCH_PATH = + "gnu.java.net.protocol|gnu.inet"; + + // Cached System ClassLoader + private static ClassLoader systemClassLoader; + + /** + * The name of the protocol for this URL. + * The protocol is always stored in lower case. + */ + private String protocol; + + /** + * The "authority" portion of the URL. + */ + private String authority; + + /** + * The hostname or IP address of this protocol. + * This includes a possible user. For example <code>joe@some.host.net</code>. + */ + private String host; + + /** + * The user information necessary to establish the connection. + */ + private String userInfo; + + /** + * The port number of this protocol or -1 if the port number used is + * the default for this protocol. + */ + private int port = -1; // Initialize for constructor using context. + + /** + * The "file" portion of the URL. It is defined as <code>path[?query]</code>. + */ + private String file; + + /** + * The anchor portion of the URL. + */ + private String ref; + + /** + * This is the hashCode for this URL + */ + private int hashCode; + + /** + * The protocol handler in use for this URL + */ + transient URLStreamHandler ph; + + /** + * If an application installs its own protocol handler factory, this is + * where we keep track of it. + */ + private static URLStreamHandlerFactory factory; + private static final long serialVersionUID = -7627629688361524110L; + + /** + * This a table where we cache protocol handlers to avoid the overhead + * of looking them up each time. + */ + private static HashMap ph_cache = new HashMap(); + + /** + * Whether or not to cache protocol handlers. + */ + private static boolean cache_handlers; + + static + { + String s = System.getProperty("gnu.java.net.nocache_protocol_handlers"); + + if (s == null) + cache_handlers = true; + else + cache_handlers = false; + } + + /** + * Constructs a URL and loads a protocol handler for the values passed as + * arguments. + * + * @param protocol The protocol for this URL ("http", "ftp", etc) + * @param host The hostname or IP address to connect to + * @param port The port number to use, or -1 to use the protocol's + * default port + * @param file The "file" portion of the URL. + * + * @exception MalformedURLException If a protocol handler cannot be loaded or + * a parse error occurs. + */ + public URL(String protocol, String host, int port, String file) + throws MalformedURLException + { + this(protocol, host, port, file, null); + } + + /** + * Constructs a URL and loads a protocol handler for the values passed in + * as arugments. Uses the default port for the protocol. + * + * @param protocol The protocol for this URL ("http", "ftp", etc) + * @param host The hostname or IP address for this URL + * @param file The "file" portion of this URL. + * + * @exception MalformedURLException If a protocol handler cannot be loaded or + * a parse error occurs. + */ + public URL(String protocol, String host, String file) + throws MalformedURLException + { + this(protocol, host, -1, file, null); + } + + /** + * This method initializes a new instance of <code>URL</code> with the + * specified protocol, host, port, and file. Additionally, this method + * allows the caller to specify a protocol handler to use instead of + * the default. If this handler is specified, the caller must have + * the "specifyStreamHandler" permission (see <code>NetPermission</code>) + * or a <code>SecurityException</code> will be thrown. + * + * @param protocol The protocol for this URL ("http", "ftp", etc) + * @param host The hostname or IP address to connect to + * @param port The port number to use, or -1 to use the protocol's default + * port + * @param file The "file" portion of the URL. + * @param ph The protocol handler to use with this URL. + * + * @exception MalformedURLException If no protocol handler can be loaded + * for the specified protocol. + * @exception SecurityException If the <code>SecurityManager</code> exists + * and does not allow the caller to specify its own protocol handler. + * + * @since 1.2 + */ + public URL(String protocol, String host, int port, String file, + URLStreamHandler ph) throws MalformedURLException + { + if (protocol == null) + throw new MalformedURLException("null protocol"); + protocol = protocol.toLowerCase(); + this.protocol = protocol; + + if (ph != null) + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new NetPermission("specifyStreamHandler")); + + this.ph = ph; + } + else + this.ph = getURLStreamHandler(protocol); + + if (this.ph == null) + throw new MalformedURLException("Protocol handler not found: " + + protocol); + + this.host = host; + this.port = port; + this.authority = (host != null) ? host : ""; + if (port >= 0 && host != null) + this.authority += ":" + port; + + int hashAt = file.indexOf('#'); + if (hashAt < 0) + { + this.file = file; + this.ref = null; + } + else + { + this.file = file.substring(0, hashAt); + this.ref = file.substring(hashAt + 1); + } + hashCode = hashCode(); // Used for serialization. + } + + /** + * Initializes a URL from a complete string specification such as + * "http://www.urbanophile.com/arenn/". First the protocol name is parsed + * out of the string. Then a handler is located for that protocol and + * the parseURL() method of that protocol handler is used to parse the + * remaining fields. + * + * @param spec The complete String representation of a URL + * + * @exception MalformedURLException If a protocol handler cannot be found + * or the URL cannot be parsed + */ + public URL(String spec) throws MalformedURLException + { + this((URL) null, spec != null ? spec : "", (URLStreamHandler) null); + } + + /** + * This method parses a String representation of a URL within the + * context of an existing URL. Principally this means that any + * fields not present the URL are inheritied from the context URL. + * This allows relative URL's to be easily constructed. If the + * context argument is null, then a complete URL must be specified + * in the URL string. If the protocol parsed out of the URL is + * different from the context URL's protocol, then then URL String + * is also expected to be a complete URL. + * + * @param context The context on which to parse the specification + * @param spec The string to parse an URL + * + * @exception MalformedURLException If a protocol handler cannot be found + * for the URL cannot be parsed + */ + public URL(URL context, String spec) throws MalformedURLException + { + this(context, spec, (URLStreamHandler) null); + } + + /** + * Creates an URL from given arguments + * This method parses a String representation of a URL within the + * context of an existing URL. Principally this means that any fields + * not present the URL are inheritied from the context URL. This allows + * relative URL's to be easily constructed. If the context argument is + * null, then a complete URL must be specified in the URL string. + * If the protocol parsed out of the URL is different + * from the context URL's protocol, then then URL String is also + * expected to be a complete URL. + * <p> + * Additionally, this method allows the caller to specify a protocol handler + * to use instead of the default. If this handler is specified, the caller + * must have the "specifyStreamHandler" permission + * (see <code>NetPermission</code>) or a <code>SecurityException</code> + * will be thrown. + * + * @param context The context in which to parse the specification + * @param spec The string to parse as an URL + * @param ph The stream handler for the URL + * + * @exception MalformedURLException If a protocol handler cannot be found + * or the URL cannot be parsed + * @exception SecurityException If the <code>SecurityManager</code> exists + * and does not allow the caller to specify its own protocol handler. + * + * @since 1.2 + */ + public URL(URL context, String spec, URLStreamHandler ph) + throws MalformedURLException + { + /* A protocol is defined by the doc as the substring before a ':' + * as long as the ':' occurs before any '/'. + * + * If context is null, then spec must be an absolute URL. + * + * The relative URL need not specify all the components of a URL. + * If the protocol, host name, or port number is missing, the value + * is inherited from the context. A bare file component is appended + * to the context's file. The optional anchor is not inherited. + */ + + // If this is an absolute URL, then ignore context completely. + // An absolute URL must have chars prior to "://" but cannot have a colon + // right after the "://". The second colon is for an optional port value + // and implies that the host from the context is used if available. + int colon; + int slash = spec.indexOf('/'); + if ((colon = spec.indexOf("://", 1)) > 0 + && ((colon < slash || slash < 0)) + && ! spec.regionMatches(colon, "://:", 0, 4)) + context = null; + + if ((colon = spec.indexOf(':')) > 0 + && (colon < slash || slash < 0)) + { + // Protocol specified in spec string. + protocol = spec.substring(0, colon).toLowerCase(); + if (context != null && context.protocol.equals(protocol)) + { + // The 1.2 doc specifically says these are copied to the new URL. + host = context.host; + port = context.port; + userInfo = context.userInfo; + authority = context.authority; + } + } + else if (context != null) + { + // Protocol NOT specified in spec string. + // Use context fields (except ref) as a foundation for relative URLs. + colon = -1; + protocol = context.protocol; + host = context.host; + port = context.port; + userInfo = context.userInfo; + if (spec.indexOf(":/", 1) < 0) + { + file = context.file; + if (file == null || file.length() == 0) + file = "/"; + } + authority = context.authority; + } + else // Protocol NOT specified in spec. and no context available. + throw new MalformedURLException("Absolute URL required with null" + + " context: " + spec); + + protocol = protocol.trim(); + + if (ph != null) + { + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkPermission(new NetPermission("specifyStreamHandler")); + + this.ph = ph; + } + else + this.ph = getURLStreamHandler(protocol); + + if (this.ph == null) + throw new MalformedURLException("Protocol handler not found: " + + protocol); + + // JDK 1.2 doc for parseURL specifically states that any '#' ref + // is to be excluded by passing the 'limit' as the indexOf the '#' + // if one exists, otherwise pass the end of the string. + int hashAt = spec.indexOf('#', colon + 1); + + try + { + this.ph.parseURL(this, spec, colon + 1, + hashAt < 0 ? spec.length() : hashAt); + } + catch (URLParseError e) + { + throw new MalformedURLException(e.getMessage()); + } + + if (hashAt >= 0) + ref = spec.substring(hashAt + 1); + + hashCode = hashCode(); // Used for serialization. + } + + /** + * Test another URL for equality with this one. This will be true only if + * the argument is non-null and all of the fields in the URL's match + * exactly (ie, protocol, host, port, file, and ref). Overrides + * Object.equals(), implemented by calling the equals method of the handler. + * + * @param obj The URL to compare with + * + * @return true if the URL is equal, false otherwise + */ + public boolean equals(Object obj) + { + if (! (obj instanceof URL)) + return false; + + return ph.equals(this, (URL) obj); + } + + /** + * Returns the contents of this URL as an object by first opening a + * connection, then calling the getContent() method against the connection + * + * @return A content object for this URL + * @exception IOException If opening the connection or getting the + * content fails. + * + * @since 1.3 + */ + public Object getContent() throws IOException + { + return openConnection().getContent(); + } + + /** + * Gets the contents of this URL + * + * @param classes The allow classes for the content object. + * + * @return a context object for this URL. + * + * @exception IOException If an error occurs + */ + public Object getContent(Class[] classes) throws IOException + { + // FIXME: implement this + return getContent(); + } + + /** + * Returns the file portion of the URL. + * Defined as <code>path[?query]</code>. + * Returns the empty string if there is no file portion. + * + * @return The filename specified in this URL, or an empty string if empty. + */ + public String getFile() + { + return file == null ? "" : file; + } + + /** + * Returns the path of the URL. This is the part of the file before any '?' + * character. + * + * @return The path specified in this URL, or null if empty. + * + * @since 1.3 + */ + public String getPath() + { + // The spec says we need to return an empty string, but some + // applications depends on receiving null when the path is empty. + if (file == null) + return null; + int quest = file.indexOf('?'); + return quest < 0 ? getFile() : file.substring(0, quest); + } + + /** + * Returns the authority of the URL + * + * @return The authority specified in this URL. + * + * @since 1.3 + */ + public String getAuthority() + { + return authority; + } + + /** + * Returns the host of the URL + * + * @return The host specified in this URL. + */ + public String getHost() + { + int at = (host == null) ? -1 : host.indexOf('@'); + return at < 0 ? host : host.substring(at + 1, host.length()); + } + + /** + * Returns the port number of this URL or -1 if the default port number is + * being used. + * + * @return The port number + * + * @see #getDefaultPort() + */ + public int getPort() + { + return port; + } + + /** + * Returns the default port of the URL. If the StreamHandler for the URL + * protocol does not define a default port it returns -1. + * + * @return The default port of the current protocol. + */ + public int getDefaultPort() + { + return ph.getDefaultPort(); + } + + /** + * Returns the protocol of the URL + * + * @return The specified protocol. + */ + public String getProtocol() + { + return protocol; + } + + /** + * Returns the ref (sometimes called the "# reference" or "anchor") portion + * of the URL. + * + * @return The ref + */ + public String getRef() + { + return ref; + } + + /** + * Returns the user information of the URL. This is the part of the host + * name before the '@'. + * + * @return the user at a particular host or null when no user defined. + */ + public String getUserInfo() + { + if (userInfo != null) + return userInfo; + int at = (host == null) ? -1 : host.indexOf('@'); + return at < 0 ? null : host.substring(0, at); + } + + /** + * Returns the query of the URL. This is the part of the file before the + * '?'. + * + * @return the query part of the file, or null when there is no query part. + */ + public String getQuery() + { + int quest = (file == null) ? -1 : file.indexOf('?'); + return quest < 0 ? null : file.substring(quest + 1, file.length()); + } + + /** + * Returns a hashcode computed by the URLStreamHandler of this URL + * + * @return The hashcode for this URL. + */ + public int hashCode() + { + if (hashCode != 0) + return hashCode; // Use cached value if available. + else + return ph.hashCode(this); + } + + /** + * Returns a URLConnection object that represents a connection to the remote + * object referred to by the URL. The URLConnection is created by calling the + * openConnection() method of the protocol handler + * + * @return A URLConnection for this URL + * + * @exception IOException If an error occurs + */ + public URLConnection openConnection() throws IOException + { + return ph.openConnection(this); + } + + /** + * Opens a connection to this URL and returns an InputStream for reading + * from that connection + * + * @return An <code>InputStream</code> for this URL. + * + * @exception IOException If an error occurs + */ + public InputStream openStream() throws IOException + { + return openConnection().getInputStream(); + } + + /** + * Tests whether or not another URL refers to the same "file" as this one. + * This will be true if and only if the passed object is not null, is a + * URL, and matches all fields but the ref (ie, protocol, host, port, + * and file); + * + * @param url The URL object to test with + * + * @return true if URL matches this URL's file, false otherwise + */ + public boolean sameFile(URL url) + { + return ph.sameFile(this, url); + } + + /** + * Sets the specified fields of the URL. This is not a public method so + * that only URLStreamHandlers can modify URL fields. This might be called + * by the <code>parseURL()</code> method in that class. URLs are otherwise + * constant. If the given protocol does not exist, it will keep the previously + * set protocol. + * + * @param protocol The protocol name for this URL + * @param host The hostname or IP address for this URL + * @param port The port number of this URL + * @param file The "file" portion of this URL. + * @param ref The anchor portion of this URL. + */ + protected void set(String protocol, String host, int port, String file, + String ref) + { + URLStreamHandler protocolHandler = null; + protocol = protocol.toLowerCase(); + if (! this.protocol.equals(protocol)) + protocolHandler = getURLStreamHandler(protocol); + + // It is an hidden feature of the JDK. If the protocol does not exist, + // we keep the previously initialized protocol. + if (protocolHandler != null) + { + this.ph = protocolHandler; + this.protocol = protocol; + } + this.authority = ""; + this.port = port; + this.host = host; + this.file = file; + this.ref = ref; + + if (host != null) + this.authority += host; + if (port >= 0) + this.authority += ":" + port; + + hashCode = hashCode(); // Used for serialization. + } + + /** + * Sets the specified fields of the URL. This is not a public method so + * that only URLStreamHandlers can modify URL fields. URLs are otherwise + * constant. If the given protocol does not exist, it will keep the previously + * set protocol. + * + * @param protocol The protocol name for this URL. + * @param host The hostname or IP address for this URL. + * @param port The port number of this URL. + * @param authority The authority of this URL. + * @param userInfo The user and password (if needed) of this URL. + * @param path The "path" portion of this URL. + * @param query The query of this URL. + * @param ref The anchor portion of this URL. + * + * @since 1.3 + */ + protected void set(String protocol, String host, int port, String authority, + String userInfo, String path, String query, String ref) + { + URLStreamHandler protocolHandler = null; + protocol = protocol.toLowerCase(); + if (! this.protocol.equals(protocol)) + protocolHandler = getURLStreamHandler(protocol); + + // It is an hidden feature of the JDK. If the protocol does not exist, + // we keep the previously initialized protocol. + if (protocolHandler != null) + { + this.ph = protocolHandler; + this.protocol = protocol; + } + this.host = host; + this.userInfo = userInfo; + this.port = port; + this.authority = authority; + if (query == null) + this.file = path; + else + this.file = path + "?" + query; + this.ref = ref; + hashCode = hashCode(); // Used for serialization. + } + + /** + * Sets the URLStreamHandlerFactory for this class. This factory is + * responsible for returning the appropriate protocol handler for + * a given URL. + * + * @param fac The URLStreamHandlerFactory class to use + * + * @exception Error If the factory is alread set. + * @exception SecurityException If a security manager exists and its + * checkSetFactory method doesn't allow the operation + */ + public static synchronized void setURLStreamHandlerFactory(URLStreamHandlerFactory fac) + { + if (factory != null) + throw new Error("URLStreamHandlerFactory already set"); + + // Throw an exception if an extant security mgr precludes + // setting the factory. + SecurityManager s = System.getSecurityManager(); + if (s != null) + s.checkSetFactory(); + factory = fac; + } + + /** + * Returns a String representing this URL. The String returned is + * created by calling the protocol handler's toExternalForm() method. + * + * @return A string for this URL + */ + public String toExternalForm() + { + // Identical to toString(). + return ph.toExternalForm(this); + } + + /** + * Returns a String representing this URL. Identical to toExternalForm(). + * The value returned is created by the protocol handler's + * toExternalForm method. Overrides Object.toString() + * + * @return A string for this URL + */ + public String toString() + { + // Identical to toExternalForm(). + return ph.toExternalForm(this); + } + + /** + * This internal method is used in two different constructors to load + * a protocol handler for this URL. + * + * @param protocol The protocol to load a handler for + * + * @return A URLStreamHandler for this protocol, or null when not found. + */ + private static synchronized URLStreamHandler getURLStreamHandler(String protocol) + { + URLStreamHandler ph = null; + + // First, see if a protocol handler is in our cache. + if (cache_handlers) + { + if ((ph = (URLStreamHandler) ph_cache.get(protocol)) != null) + return ph; + } + + // If a non-default factory has been set, use it to find the protocol. + if (factory != null) + { + ph = factory.createURLStreamHandler(protocol); + } + else if (protocol.equals("core")) + { + ph = new gnu.java.net.protocol.core.Handler(); + } + else if (protocol.equals("file")) + { + // This is an interesting case. It's tempting to think that we + // could call Class.forName ("gnu.java.net.protocol.file.Handler") to + // get the appropriate class. Unfortunately, if we do that the + // program will never terminate, because getURLStreamHandler is + // eventually called by Class.forName. + // + // Treating "file" as a special case is the minimum that will + // fix this problem. If other protocols are required in a + // statically linked application they will need to be handled in + // the same way as "file". + ph = new gnu.java.net.protocol.file.Handler(); + } + + // Non-default factory may have returned null or a factory wasn't set. + // Use the default search algorithm to find a handler for this protocol. + if (ph == null) + { + // Get the list of packages to check and append our default handler + // to it, along with the JDK specified default as a last resort. + // Except in very unusual environments the JDK specified one shouldn't + // ever be needed (or available). + String ph_search_path = + System.getProperty("java.protocol.handler.pkgs"); + + // Tack our default package on at the ends. + if (ph_search_path != null) + ph_search_path += "|" + DEFAULT_SEARCH_PATH; + else + ph_search_path = DEFAULT_SEARCH_PATH; + + // Finally loop through our search path looking for a match. + StringTokenizer pkgPrefix = new StringTokenizer(ph_search_path, "|"); + + // Cache the systemClassLoader + if (systemClassLoader == null) + { + systemClassLoader = (ClassLoader) AccessController.doPrivileged + (new PrivilegedAction() { + public Object run() + { + return ClassLoader.getSystemClassLoader(); + } + }); + } + + do + { + try + { + // Try to get a class from the system/application + // classloader, initialize it, make an instance + // and try to cast it to a URLStreamHandler. + String clsName = + (pkgPrefix.nextToken() + "." + protocol + ".Handler"); + Class c = Class.forName(clsName, true, systemClassLoader); + ph = (URLStreamHandler) c.newInstance(); + } + catch (ThreadDeath death) + { + throw death; + } + catch (Throwable t) + { + // Ignored. + } + } + while (ph == null && pkgPrefix.hasMoreTokens()); + } + + // Update the hashtable with the new protocol handler. + if (ph != null && cache_handlers) + ph_cache.put(protocol, ph); + else + ph = null; + + return ph; + } + + private void readObject(ObjectInputStream ois) + throws IOException, ClassNotFoundException + { + ois.defaultReadObject(); + this.ph = getURLStreamHandler(protocol); + if (this.ph == null) + throw new IOException("Handler for protocol " + protocol + " not found"); + } + + private void writeObject(ObjectOutputStream oos) throws IOException + { + oos.defaultWriteObject(); + } + + /** + * Returns the equivalent <code>URI</code> object for this <code>URL</code>. + * This is the same as calling <code>new URI(this.toString())</code>. + * RFC2396-compliant URLs are guaranteed a successful conversion to + * a <code>URI</code> instance. However, there are some values which + * form valid URLs, but which do not also form RFC2396-compliant URIs. + * + * @throws URISyntaxException if this URL is not RFC2396-compliant, + * and thus can not be successfully converted to a URI. + */ + public URI toURI() + throws URISyntaxException + { + return new URI(toString()); + } + +} diff --git a/gcc-4.2.1/libjava/java/net/URLClassLoader.java b/gcc-4.2.1/libjava/java/net/URLClassLoader.java new file mode 100644 index 000000000..06db7d582 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/URLClassLoader.java @@ -0,0 +1,1452 @@ +/* URLClassLoader.java -- ClassLoader that loads classes from one or more URLs + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.net; + +import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.security.AccessControlContext; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.PrivilegedAction; +import java.security.SecureClassLoader; +import java.security.cert.Certificate; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import gnu.gcj.runtime.SharedLibHelper; +import gnu.gcj.Core; +import gnu.java.net.protocol.core.CoreInputStream; + +/** + * A secure class loader that can load classes and resources from + * multiple locations. Given an array of <code>URL</code>s this class + * loader will retrieve classes and resources by fetching them from + * possible remote locations. Each <code>URL</code> is searched in + * order in which it was added. If the file portion of the + * <code>URL</code> ends with a '/' character then it is interpreted + * as a base directory, otherwise it is interpreted as a jar file from + * which the classes/resources are resolved. + * + * <p>New instances can be created by two static + * <code>newInstance()</code> methods or by three public + * contructors. Both ways give the option to supply an initial array + * of <code>URL</code>s and (optionally) a parent classloader (that is + * different from the standard system class loader).</p> + * + * <p>Normally creating a <code>URLClassLoader</code> throws a + * <code>SecurityException</code> if a <code>SecurityManager</code> is + * installed and the <code>checkCreateClassLoader()</code> method does + * not return true. But the <code>newInstance()</code> methods may be + * used by any code as long as it has permission to acces the given + * <code>URL</code>s. <code>URLClassLoaders</code> created by the + * <code>newInstance()</code> methods also explicitly call the + * <code>checkPackageAccess()</code> method of + * <code>SecurityManager</code> if one is installed before trying to + * load a class. Note that only subclasses of + * <code>URLClassLoader</code> can add new URLs after the + * URLClassLoader had been created. But it is always possible to get + * an array of all URLs that the class loader uses to resolve classes + * and resources by way of the <code>getURLs()</code> method.</p> + * + * <p>Open issues: + * <ul> + * + * <li>Should the URLClassLoader actually add the locations found in + * the manifest or is this the responsibility of some other + * loader/(sub)class? (see <a + * href="http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html"> + * Extension Mechanism Architecture - Bundles Extensions</a>)</li> + * + * <li>How does <code>definePackage()</code> and sealing work + * precisely?</li> + * + * <li>We save and use the security context (when a created by + * <code>newInstance()</code> but do we have to use it in more + * places?</li> + * + * <li>The use of <code>URLStreamHandler</code>s has not been tested.</li> + * + * </ul> + * </p> + * + * @since 1.2 + * + * @author Mark Wielaard (mark@klomp.org) + * @author Wu Gansha (gansha.wu@intel.com) + */ +public class URLClassLoader extends SecureClassLoader +{ + // Class Variables + + /** + * A global cache to store mappings between URLLoader and URL, + * so we can avoid do all the homework each time the same URL + * comes. + * XXX - Keeps these loaders forever which prevents garbage collection. + */ + private static HashMap urlloaders = new HashMap(); + + /** + * A cache to store mappings between handler factory and its + * private protocol handler cache (also a HashMap), so we can avoid + * create handlers each time the same protocol comes. + */ + private static HashMap factoryCache = new HashMap(5); + + // Instance variables + + /** Locations to load classes from */ + private final Vector urls = new Vector(); + + /** + * Store pre-parsed information for each url into this vector: each + * element is a URL loader. A jar file has its own class-path + * attribute which adds to the URLs that will be searched, but this + * does not add to the list of urls. + */ + private final Vector urlinfos = new Vector(); + + /** Factory used to get the protocol handlers of the URLs */ + private final URLStreamHandlerFactory factory; + + /** + * The security context when created from <code>newInstance()</code> + * or null when created through a normal constructor or when no + * <code>SecurityManager</code> was installed. + */ + private final AccessControlContext securityContext; + + // Helper classes + + /** + * A <code>URLLoader</code> contains all logic to load resources from a + * given base <code>URL</code>. + */ + abstract static class URLLoader + { + /** + * Our classloader to get info from if needed. + */ + final URLClassLoader classloader; + + /** + * The base URL from which all resources are loaded. + */ + final URL baseURL; + + /** + * A <code>CodeSource</code> without any associated certificates. + * It is common for classes to not have certificates associated + * with them. If they come from the same <code>URLLoader</code> + * then it is safe to share the associated <code>CodeSource</code> + * between them since <code>CodeSource</code> is immutable. + */ + final CodeSource noCertCodeSource; + + URLLoader(URLClassLoader classloader, URL baseURL) + { + this(classloader, baseURL, baseURL); + } + + URLLoader(URLClassLoader classloader, URL baseURL, URL overrideURL) + { + this.classloader = classloader; + this.baseURL = baseURL; + this.noCertCodeSource = new CodeSource(overrideURL, null); + } + + /** + * Returns a <code>Class</code> loaded by this + * <code>URLLoader</code>, or <code>null</code> when this loader + * either can't load the class or doesn't know how to load classes + * at all. + */ + Class getClass(String className) + { + return null; + } + + /** + * Returns a <code>Resource</code> loaded by this + * <code>URLLoader</code>, or <code>null</code> when no + * <code>Resource</code> with the given name exists. + */ + abstract Resource getResource(String s); + + /** + * Returns the <code>Manifest</code> associated with the + * <code>Resource</code>s loaded by this <code>URLLoader</code> or + * <code>null</code> there is no such <code>Manifest</code>. + */ + Manifest getManifest() + { + return null; + } + + Vector getClassPath() + { + return null; + } + } + + /** + * A <code>Resource</code> represents a resource in some + * <code>URLLoader</code>. It also contains all information (e.g., + * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and + * <code>InputStream</code>) that is necessary for loading resources + * and creating classes from a <code>URL</code>. + */ + abstract static class Resource + { + final URLLoader loader; + + Resource(URLLoader loader) + { + this.loader = loader; + } + + /** + * Returns the non-null <code>CodeSource</code> associated with + * this resource. + */ + CodeSource getCodeSource() + { + Certificate[] certs = getCertificates(); + if (certs == null) + return loader.noCertCodeSource; + else + return new CodeSource(loader.baseURL, certs); + } + + /** + * Returns <code>Certificates</code> associated with this + * resource, or null when there are none. + */ + Certificate[] getCertificates() + { + return null; + } + + /** + * Return a <code>URL</code> that can be used to access this resource. + */ + abstract URL getURL(); + + /** + * Returns the size of this <code>Resource</code> in bytes or + * <code>-1</code> when unknown. + */ + abstract int getLength(); + + /** + * Returns the non-null <code>InputStream</code> through which + * this resource can be loaded. + */ + abstract InputStream getInputStream() throws IOException; + } + + /** + * A <code>JarURLLoader</code> is a type of <code>URLLoader</code> + * only loading from jar url. + */ + static final class JarURLLoader extends URLLoader + { + final JarFile jarfile; // The jar file for this url + final URL baseJarURL; // Base jar: url for all resources loaded from jar + + Vector classPath; // The "Class-Path" attribute of this Jar's manifest + + public JarURLLoader(URLClassLoader classloader, URL baseURL, + URL absoluteUrl) + { + super(classloader, baseURL, absoluteUrl); + + // Cache url prefix for all resources in this jar url. + String external = baseURL.toExternalForm(); + StringBuffer sb = new StringBuffer(external.length() + 6); + sb.append("jar:"); + sb.append(external); + sb.append("!/"); + String jarURL = sb.toString(); + + this.classPath = null; + URL baseJarURL = null; + JarFile jarfile = null; + try + { + baseJarURL = + new URL(null, jarURL, classloader.getURLStreamHandler("jar")); + + jarfile = + ((JarURLConnection) baseJarURL.openConnection()).getJarFile(); + + Manifest manifest; + Attributes attributes; + String classPathString; + + if ((manifest = jarfile.getManifest()) != null + && (attributes = manifest.getMainAttributes()) != null + && ((classPathString + = attributes.getValue(Attributes.Name.CLASS_PATH)) + != null)) + { + this.classPath = new Vector(); + + StringTokenizer st = new StringTokenizer(classPathString, " "); + while (st.hasMoreElements ()) + { + String e = st.nextToken (); + try + { + URL url = new URL(baseURL, e); + this.classPath.add(url); + } + catch (java.net.MalformedURLException xx) + { + // Give up + } + } + } + } + catch (IOException ioe) + { + /* ignored */ + } + + this.baseJarURL = baseJarURL; + this.jarfile = jarfile; + } + + /** get resource with the name "name" in the jar url */ + Resource getResource(String name) + { + if (jarfile == null) + return null; + + if (name.startsWith("/")) + name = name.substring(1); + + JarEntry je = jarfile.getJarEntry(name); + if (je != null) + return new JarURLResource(this, name, je); + else + return null; + } + + Manifest getManifest() + { + try + { + return (jarfile == null) ? null : jarfile.getManifest(); + } + catch (IOException ioe) + { + return null; + } + } + + Vector getClassPath() + { + return classPath; + } + } + + static final class JarURLResource extends Resource + { + private final JarEntry entry; + private final String name; + + JarURLResource(JarURLLoader loader, String name, JarEntry entry) + { + super(loader); + this.entry = entry; + this.name = name; + } + + InputStream getInputStream() throws IOException + { + return ((JarURLLoader) loader).jarfile.getInputStream(entry); + } + + int getLength() + { + return (int) entry.getSize(); + } + + Certificate[] getCertificates() + { + // We have to get the entry from the jar file again, because the + // certificates will not be available until the entire entry has + // been read. + return ((JarEntry) ((JarURLLoader) loader).jarfile.getEntry(name)) + .getCertificates(); + } + + URL getURL() + { + try + { + return new URL(((JarURLLoader) loader).baseJarURL, name, + loader.classloader.getURLStreamHandler("jar")); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } + } + + /** + * Loader for remote directories. + */ + static final class RemoteURLLoader extends URLLoader + { + private final String protocol; + + RemoteURLLoader(URLClassLoader classloader, URL url) + { + super(classloader, url); + protocol = url.getProtocol(); + } + + /** + * Get a remote resource. + * Returns null if no such resource exists. + */ + Resource getResource(String name) + { + try + { + URL url = + new URL(baseURL, name, classloader.getURLStreamHandler(protocol)); + URLConnection connection = url.openConnection(); + + // Open the connection and check the stream + // just to be sure it exists. + int length = connection.getContentLength(); + InputStream stream = connection.getInputStream(); + + // We can do some extra checking if it is a http request + if (connection instanceof HttpURLConnection) + { + int response = + ((HttpURLConnection) connection).getResponseCode(); + if (response / 100 != 2) + return null; + } + + if (stream != null) + return new RemoteResource(this, name, url, stream, length); + else + return null; + } + catch (IOException ioe) + { + return null; + } + } + } + + /** + * A resource from some remote location. + */ + static final class RemoteResource extends Resource + { + private final URL url; + private final InputStream stream; + private final int length; + + RemoteResource(RemoteURLLoader loader, String name, URL url, + InputStream stream, int length) + { + super(loader); + this.url = url; + this.stream = stream; + this.length = length; + } + + InputStream getInputStream() throws IOException + { + return stream; + } + + public int getLength() + { + return length; + } + + public URL getURL() + { + return url; + } + } + + /** + * A <code>SoURLLoader</code> is a type of <code>URLLoader</code> + * that loads classes and resources from a shared library. + */ + final static class SoURLLoader extends URLLoader + { + SharedLibHelper helper; + + SoURLLoader(URLClassLoader classloader, URL url) + { + this(classloader, url, url); + } + + SoURLLoader(URLClassLoader classloader, URL url, URL overrideURL) + { + super(classloader, url, overrideURL); + helper = SharedLibHelper.findHelper(classloader, url.getFile(), + noCertCodeSource, true); + } + + Class getClass(String className) + { + return helper.findClass(className); + } + + Resource getResource(String name) + { + URL url = helper.findResource(name); + if (url == null) + return null; + return new SoResource(this, url); + } + } + + final static class SoResource extends Resource + { + SoResource(SoURLLoader loader, URL url) + { + super(loader); + this.url = url; + } + + InputStream getInputStream() throws IOException + { + URLConnection conn = url.openConnection(); + return conn.getInputStream(); + } + + public int getLength() + { + // FIXME we could find this by asking the core object. + return -1; + } + + public URL getURL () + { + return url; + } + + final URL url; + } + + /** + * A <code>FileURLLoader</code> is a type of <code>URLLoader</code> + * only loading from file url. + */ + static final class FileURLLoader extends URLLoader + { + File dir; //the file for this file url + + FileURLLoader(URLClassLoader classloader, URL url, URL absoluteUrl) + { + super(classloader, url, absoluteUrl); + dir = new File(absoluteUrl.getFile()); + } + + /** get resource with the name "name" in the file url */ + Resource getResource(String name) + { + try + { + File file = new File(dir, name).getCanonicalFile(); + if (file.exists() && !file.isDirectory()) + return new FileResource(this, file); + } + catch (IOException e) + { + // Fall through... + } + return null; + } + } + + static final class FileResource extends Resource + { + final File file; + + FileResource(FileURLLoader loader, File file) + { + super(loader); + this.file = file; + } + + InputStream getInputStream() throws IOException + { + // Delegate to the URL content handler mechanism to retrieve an + // HTML representation of the directory listing if a directory + if (file.isDirectory()) + { + URL url = getURL(); + return url.openStream(); + } + // Otherwise simply return a FileInputStream + return new FileInputStream(file); + } + + public int getLength() + { + // Delegate to the URL content handler mechanism to retrieve the + // length of the HTML representation of the directory listing if + // a directory, or -1 if an exception occurs opening the directory. + if (file.isDirectory()) + { + URL url = getURL(); + try + { + URLConnection connection = url.openConnection(); + return connection.getContentLength(); + } + catch (IOException e) + { + return -1; + } + } + // Otherwise simply return the file length + return (int) file.length(); + } + + public URL getURL() + { + try + { + return file.toURL(); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } + } + + /** + * A <code>CoreURLLoader</code> is a type of <code>URLLoader</code> + * only loading from core url. + */ + static final class CoreURLLoader extends URLLoader + { + private String dir; + + CoreURLLoader(URLClassLoader classloader, URL url) + { + super(classloader, url); + dir = baseURL.getFile(); + } + + /** get resource with the name "name" in the core url */ + Resource getResource(String name) + { + Core core = Core.find (dir + name); + if (core != null) + return new CoreResource(this, name, core); + return null; + } + } + + static final class CoreResource extends Resource + { + private final Core core; + private final String name; + + CoreResource(CoreURLLoader loader, String name, Core core) + { + super(loader); + this.core = core; + this.name = name; + } + + InputStream getInputStream() throws IOException + { + return new CoreInputStream(core); + } + + public int getLength() + { + return core.length; + } + + public URL getURL() + { + try + { + return new URL(loader.baseURL, name, + loader.classloader.getURLStreamHandler("core")); + } + catch (MalformedURLException e) + { + InternalError ie = new InternalError(); + ie.initCause(e); + throw ie; + } + } + } + + // Constructors + + /** + * Creates a URLClassLoader that gets classes from the supplied URLs. + * To determine if this classloader may be created the constructor of + * the super class (<code>SecureClassLoader</code>) is called first, which + * can throw a SecurityException. Then the supplied URLs are added + * in the order given to the URLClassLoader which uses these URLs to + * load classes and resources (after using the default parent ClassLoader). + * + * @param urls Locations that should be searched by this ClassLoader when + * resolving Classes or Resources. + * @exception SecurityException if the SecurityManager disallows the + * creation of a ClassLoader. + * @see SecureClassLoader + */ + public URLClassLoader(URL[] urls) throws SecurityException + { + super(); + this.factory = null; + this.securityContext = null; + addURLs(urls); + } + + /** + * Creates a <code>URLClassLoader</code> that gets classes from the supplied + * <code>URL</code>s. + * To determine if this classloader may be created the constructor of + * the super class (<code>SecureClassLoader</code>) is called first, which + * can throw a SecurityException. Then the supplied URLs are added + * in the order given to the URLClassLoader which uses these URLs to + * load classes and resources (after using the supplied parent ClassLoader). + * @param urls Locations that should be searched by this ClassLoader when + * resolving Classes or Resources. + * @param parent The parent class loader used before trying this class + * loader. + * @exception SecurityException if the SecurityManager disallows the + * creation of a ClassLoader. + * @exception SecurityException + * @see SecureClassLoader + */ + public URLClassLoader(URL[] urls, ClassLoader parent) + throws SecurityException + { + super(parent); + this.factory = null; + this.securityContext = null; + addURLs(urls); + } + + // Package-private to avoid a trampoline constructor. + /** + * Package-private constructor used by the static + * <code>newInstance(URL[])</code> method. Creates an + * <code>URLClassLoader</code> with the given parent but without any + * <code>URL</code>s yet. This is used to bypass the normal security + * check for creating classloaders, but remembers the security + * context which will be used when defining classes. The + * <code>URL</code>s to load from must be added by the + * <code>newInstance()</code> method in the security context of the + * caller. + * + * @param securityContext the security context of the unprivileged code. + */ + URLClassLoader(ClassLoader parent, AccessControlContext securityContext) + { + super(parent); + this.factory = null; + this.securityContext = securityContext; + } + + /** + * Creates a URLClassLoader that gets classes from the supplied URLs. + * To determine if this classloader may be created the constructor of + * the super class (<CODE>SecureClassLoader</CODE>) is called first, which + * can throw a SecurityException. Then the supplied URLs are added + * in the order given to the URLClassLoader which uses these URLs to + * load classes and resources (after using the supplied parent ClassLoader). + * It will use the supplied <CODE>URLStreamHandlerFactory</CODE> to get the + * protocol handlers of the supplied URLs. + * @param urls Locations that should be searched by this ClassLoader when + * resolving Classes or Resources. + * @param parent The parent class loader used before trying this class + * loader. + * @param factory Used to get the protocol handler for the URLs. + * @exception SecurityException if the SecurityManager disallows the + * creation of a ClassLoader. + * @exception SecurityException + * @see SecureClassLoader + */ + public URLClassLoader(URL[] urls, ClassLoader parent, + URLStreamHandlerFactory factory) + throws SecurityException + { + super(parent); + this.securityContext = null; + this.factory = factory; + addURLs(urls); + + // If this factory is still not in factoryCache, add it, + // since we only support three protocols so far, 5 is enough + // for cache initial size + synchronized (factoryCache) + { + if (factory != null && factoryCache.get(factory) == null) + factoryCache.put(factory, new HashMap(5)); + } + } + + // Methods + + /** + * Adds a new location to the end of the internal URL store. + * @param newUrl the location to add + */ + protected void addURL(URL newUrl) + { + urls.add(newUrl); + addURLImpl(newUrl); + } + + private void addURLImpl(URL newUrl) + { + synchronized (this) + { + if (newUrl == null) + return; // Silently ignore... + + // Reset the toString() value. + thisString = null; + + // Check global cache to see if there're already url loader + // for this url. + URLLoader loader = (URLLoader) urlloaders.get(newUrl); + if (loader == null) + { + String file = newUrl.getFile(); + String protocol = newUrl.getProtocol(); + + // If we have a file: URL, we want to make it absolute + // here, before we decide whether it is really a jar. + URL absoluteURL; + if ("file".equals (protocol)) + { + File dir = new File(file); + URL absUrl; + try + { + absoluteURL = dir.getCanonicalFile().toURL(); + } + catch (IOException ignore) + { + try + { + absoluteURL = dir.getAbsoluteFile().toURL(); + } + catch (MalformedURLException _) + { + // This really should not happen. + absoluteURL = newUrl; + } + } + } + else + { + // This doesn't hurt, and it simplifies the logic a + // little. + absoluteURL = newUrl; + } + + // Check that it is not a directory + if ("gcjlib".equals(protocol)) + loader = new SoURLLoader(this, newUrl); + else if (! (file.endsWith("/") || file.endsWith(File.separator))) + loader = new JarURLLoader(this, newUrl, absoluteURL); + else if ("file".equals(protocol)) + loader = new FileURLLoader(this, newUrl, absoluteURL); + else if ("core".equals(protocol)) + loader = new CoreURLLoader(this, newUrl); + else + loader = new RemoteURLLoader(this, newUrl); + + // Cache it. + urlloaders.put(newUrl, loader); + } + + urlinfos.add(loader); + + Vector extraUrls = loader.getClassPath(); + if (extraUrls != null) + { + Iterator it = extraUrls.iterator(); + while (it.hasNext()) + { + URL url = (URL)it.next(); + URLLoader extraLoader = (URLLoader) urlloaders.get(url); + if (! urlinfos.contains (extraLoader)) + addURLImpl(url); + } + } + + } + } + + /** + * Adds an array of new locations to the end of the internal URL + * store. Called from the the constructors. Should not call to the + * protected addURL() method since that can be overridden and + * subclasses are not yet in a good state at this point. + * jboss 4.0.3 for example depends on this. + * + * @param newUrls the locations to add + */ + private void addURLs(URL[] newUrls) + { + for (int i = 0; i < newUrls.length; i++) + { + urls.add(newUrls[i]); + addURLImpl(newUrls[i]); + } + } + + /** + * Look in both Attributes for a given value. The first Attributes + * object, if not null, has precedence. + */ + private String getAttributeValue(Attributes.Name name, Attributes first, + Attributes second) + { + String result = null; + if (first != null) + result = first.getValue(name); + if (result == null) + result = second.getValue(name); + return result; + } + + /** + * Defines a Package based on the given name and the supplied manifest + * information. The manifest indicates the title, version and + * vendor information of the specification and implementation and whether the + * package is sealed. If the Manifest indicates that the package is sealed + * then the Package will be sealed with respect to the supplied URL. + * + * @param name The name of the package + * @param manifest The manifest describing the specification, + * implementation and sealing details of the package + * @param url the code source url to seal the package + * @return the defined Package + * @throws IllegalArgumentException If this package name already exists + * in this class loader + */ + protected Package definePackage(String name, Manifest manifest, URL url) + throws IllegalArgumentException + { + // Compute the name of the package as it may appear in the + // Manifest. + StringBuffer xform = new StringBuffer(name); + for (int i = xform.length () - 1; i >= 0; --i) + if (xform.charAt(i) == '.') + xform.setCharAt(i, '/'); + xform.append('/'); + String xformName = xform.toString(); + + Attributes entryAttr = manifest.getAttributes(xformName); + Attributes attr = manifest.getMainAttributes(); + + String specTitle + = getAttributeValue(Attributes.Name.SPECIFICATION_TITLE, + entryAttr, attr); + String specVersion + = getAttributeValue(Attributes.Name.SPECIFICATION_VERSION, + entryAttr, attr); + String specVendor + = getAttributeValue(Attributes.Name.SPECIFICATION_VENDOR, + entryAttr, attr); + String implTitle + = getAttributeValue(Attributes.Name.IMPLEMENTATION_TITLE, + entryAttr, attr); + String implVersion + = getAttributeValue(Attributes.Name.IMPLEMENTATION_VERSION, + entryAttr, attr); + String implVendor + = getAttributeValue(Attributes.Name.IMPLEMENTATION_VENDOR, + entryAttr, attr); + + // Look if the Manifest indicates that this package is sealed + // XXX - most likely not completely correct! + // Shouldn't we also check the sealed attribute of the complete jar? + // http://java.sun.com/products/jdk/1.4/docs/guide/extensions/spec.html#bundled + // But how do we get that jar manifest here? + String sealed = attr.getValue(Attributes.Name.SEALED); + if ("false".equals(sealed)) + // make sure that the URL is null so the package is not sealed + url = null; + + return definePackage(name, + specTitle, specVendor, specVersion, + implTitle, implVendor, implVersion, + url); + } + + /** + * Finds (the first) class by name from one of the locations. The locations + * are searched in the order they were added to the URLClassLoader. + * + * @param className the classname to find + * @exception ClassNotFoundException when the class could not be found or + * loaded + * @return a Class object representing the found class + */ + protected Class findClass(final String className) + throws ClassNotFoundException + { + // Just try to find the resource by the (almost) same name + String resourceName = className.replace('.', '/') + ".class"; + int max = urlinfos.size(); + Resource resource = null; + for (int i = 0; i < max && resource == null; i++) + { + URLLoader loader = (URLLoader)urlinfos.elementAt(i); + if (loader == null) + continue; + + Class k = loader.getClass(className); + if (k != null) + return k; + + resource = loader.getResource(resourceName); + } + if (resource == null) + { + String message = className + " not found"; + if (runtimeInitialized()) + message += " in " + this; + throw new ClassNotFoundException(message); + } + + // Try to read the class data, create the CodeSource, Package and + // construct the class (and watch out for those nasty IOExceptions) + try + { + byte[] data; + InputStream in = resource.getInputStream(); + try + { + int length = resource.getLength(); + if (length != -1) + { + // We know the length of the data. + // Just try to read it in all at once + data = new byte[length]; + int pos = 0; + while (length - pos > 0) + { + int len = in.read(data, pos, length - pos); + if (len == -1) + throw new EOFException("Not enough data reading from: " + + in); + pos += len; + } + } + else + { + // We don't know the data length. + // Have to read it in chunks. + ByteArrayOutputStream out = new ByteArrayOutputStream(4096); + byte[] b = new byte[4096]; + int l = 0; + while (l != -1) + { + l = in.read(b); + if (l != -1) + out.write(b, 0, l); + } + data = out.toByteArray(); + } + } + finally + { + in.close(); + } + final byte[] classData = data; + + // Now get the CodeSource + final CodeSource source = resource.getCodeSource(); + + // Find out package name + String packageName = null; + int lastDot = className.lastIndexOf('.'); + if (lastDot != -1) + packageName = className.substring(0, lastDot); + + if (packageName != null && getPackage(packageName) == null) + { + // define the package + Manifest manifest = resource.loader.getManifest(); + if (manifest == null) + definePackage(packageName, null, null, null, null, null, null, + null); + else + definePackage(packageName, manifest, resource.loader.baseURL); + } + + // And finally construct the class! + SecurityManager sm = System.getSecurityManager(); + Class result = null; + if (sm != null && securityContext != null) + { + result = (Class)AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + return defineClass(className, classData, + 0, classData.length, + source); + } + }, securityContext); + } + else + result = defineClass(className, classData, 0, classData.length, source); + + // Avoid NullPointerExceptions. + Certificate[] resourceCertificates = resource.getCertificates(); + if(resourceCertificates != null) + super.setSigners(result, resourceCertificates); + + return result; + } + catch (IOException ioe) + { + ClassNotFoundException cnfe; + cnfe = new ClassNotFoundException(className + " not found in " + this); + cnfe.initCause(ioe); + throw cnfe; + } + } + + // Cached String representation of this URLClassLoader + private String thisString; + + /** + * Returns a String representation of this URLClassLoader giving the + * actual Class name, the URLs that are searched and the parent + * ClassLoader. + */ + public String toString() + { + synchronized (this) + { + if (thisString == null) + { + StringBuffer sb = new StringBuffer(); + sb.append(this.getClass().getName()); + sb.append("{urls=[" ); + URL[] thisURLs = getURLs(); + for (int i = 0; i < thisURLs.length; i++) + { + sb.append(thisURLs[i]); + if (i < thisURLs.length - 1) + sb.append(','); + } + sb.append(']'); + sb.append(", parent="); + sb.append(getParent()); + sb.append('}'); + thisString = sb.toString(); + } + return thisString; + } + } + + /** + * Finds the first occurrence of a resource that can be found. The locations + * are searched in the order they were added to the URLClassLoader. + * + * @param resourceName the resource name to look for + * @return the URLResource for the resource if found, null otherwise + */ + private Resource findURLResource(String resourceName) + { + int max = urlinfos.size(); + for (int i = 0; i < max; i++) + { + URLLoader loader = (URLLoader) urlinfos.elementAt(i); + if (loader == null) + continue; + + Resource resource = loader.getResource(resourceName); + if (resource != null) + return resource; + } + return null; + } + + /** + * Finds the first occurrence of a resource that can be found. + * + * @param resourceName the resource name to look for + * @return the URL if found, null otherwise + */ + public URL findResource(String resourceName) + { + Resource resource = findURLResource(resourceName); + if (resource != null) + return resource.getURL(); + + // Resource not found + return null; + } + + /** + * If the URLStreamHandlerFactory has been set this return the appropriate + * URLStreamHandler for the given protocol, if not set returns null. + * + * @param protocol the protocol for which we need a URLStreamHandler + * @return the appropriate URLStreamHandler or null + */ + URLStreamHandler getURLStreamHandler(String protocol) + { + if (factory == null) + return null; + + URLStreamHandler handler; + synchronized (factoryCache) + { + // Check if there're handler for the same protocol in cache. + HashMap cache = (HashMap) factoryCache.get(factory); + handler = (URLStreamHandler) cache.get(protocol); + if (handler == null) + { + // Add it to cache. + handler = factory.createURLStreamHandler(protocol); + cache.put(protocol, handler); + } + } + return handler; + } + + /** + * Finds all the resources with a particular name from all the locations. + * + * @param resourceName the name of the resource to lookup + * @return a (possible empty) enumeration of URLs where the resource can be + * found + * @exception IOException when an error occurs accessing one of the + * locations + */ + public Enumeration findResources(String resourceName) + throws IOException + { + Vector resources = new Vector(); + int max = urlinfos.size(); + for (int i = 0; i < max; i++) + { + URLLoader loader = (URLLoader) urlinfos.elementAt(i); + Resource resource = loader.getResource(resourceName); + if (resource != null) + resources.add(resource.getURL()); + } + return resources.elements(); + } + + /** + * Returns the permissions needed to access a particular code + * source. These permissions includes those returned by + * <code>SecureClassLoader.getPermissions()</code> and the actual + * permissions to access the objects referenced by the URL of the + * code source. The extra permissions added depend on the protocol + * and file portion of the URL in the code source. If the URL has + * the "file" protocol ends with a '/' character then it must be a + * directory and a file Permission to read everything in that + * directory and all subdirectories is added. If the URL had the + * "file" protocol and doesn't end with a '/' character then it must + * be a normal file and a file permission to read that file is + * added. If the <code>URL</code> has any other protocol then a + * socket permission to connect and accept connections from the host + * portion of the URL is added. + * + * @param source The codesource that needs the permissions to be accessed + * @return the collection of permissions needed to access the code resource + * @see java.security.SecureClassLoader#getPermissions(CodeSource) + */ + protected PermissionCollection getPermissions(CodeSource source) + { + // XXX - This implementation does exactly as the Javadoc describes. + // But maybe we should/could use URLConnection.getPermissions()? + // First get the permissions that would normally be granted + PermissionCollection permissions = super.getPermissions(source); + + // Now add any extra permissions depending on the URL location. + URL url = source.getLocation(); + String protocol = url.getProtocol(); + if (protocol.equals("file")) + { + String file = url.getFile(); + + // If the file end in / it must be an directory. + if (file.endsWith("/") || file.endsWith(File.separator)) + { + // Grant permission to read everything in that directory and + // all subdirectories. + permissions.add(new FilePermission(file + "-", "read")); + } + else + { + // It is a 'normal' file. + // Grant permission to access that file. + permissions.add(new FilePermission(file, "read")); + } + } + else + { + // Grant permission to connect to and accept connections from host + String host = url.getHost(); + if (host != null) + permissions.add(new SocketPermission(host, "connect,accept")); + } + + return permissions; + } + + /** + * Returns all the locations that this class loader currently uses the + * resolve classes and resource. This includes both the initially supplied + * URLs as any URLs added later by the loader. + * @return All the currently used URLs + */ + public URL[] getURLs() + { + return (URL[]) urls.toArray(new URL[urls.size()]); + } + + /** + * Creates a new instance of a <code>URLClassLoader</code> that gets + * classes from the supplied <code>URL</code>s. This class loader + * will have as parent the standard system class loader. + * + * @param urls the initial URLs used to resolve classes and + * resources + * + * @return the class loader + * + * @exception SecurityException when the calling code does not have + * permission to access the given <code>URL</code>s + */ + public static URLClassLoader newInstance(URL[] urls) + throws SecurityException + { + return newInstance(urls, null); + } + + /** + * Creates a new instance of a <code>URLClassLoader</code> that gets + * classes from the supplied <code>URL</code>s and with the supplied + * loader as parent class loader. + * + * @param urls the initial URLs used to resolve classes and + * resources + * @param parent the parent class loader + * + * @return the class loader + * + * @exception SecurityException when the calling code does not have + * permission to access the given <code>URL</code>s + */ + public static URLClassLoader newInstance(URL[] urls, final ClassLoader parent) + throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) + return new URLClassLoader(urls, parent); + else + { + final Object securityContext = sm.getSecurityContext(); + + // XXX - What to do with anything else then an AccessControlContext? + if (! (securityContext instanceof AccessControlContext)) + throw new SecurityException("securityContext must be AccessControlContext: " + + securityContext); + + URLClassLoader loader = + (URLClassLoader) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return new URLClassLoader(parent, + (AccessControlContext) securityContext); + } + }); + loader.addURLs(urls); + return loader; + } + } + + /** + * Tell whether runtime initialization is complete. + * + * @return whether runtime initialization is complete. + */ + private static native boolean runtimeInitialized(); +} diff --git a/gcc-4.2.1/libjava/java/net/VMInetAddress.java b/gcc-4.2.1/libjava/java/net/VMInetAddress.java new file mode 100644 index 000000000..b10cf2528 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/VMInetAddress.java @@ -0,0 +1,117 @@ +/* VMInetAddress.java -- Class to model an Internet address + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.net; + +import gnu.classpath.Configuration; + +import java.io.Serializable; + +class VMInetAddress implements Serializable +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + System.loadLibrary("javanet"); + } + + /** + * This method looks up the hostname of the local machine + * we are on. If the actual hostname cannot be determined, then the + * value "localhost" will be used. This native method wrappers the + * "gethostname" function. + * + * @return The local hostname. + */ + public static String getLocalHostname() + { + return InetAddress.getLocalHostname(); + } + + /** + * Returns the value of the special address INADDR_ANY + */ + public static byte[] lookupInaddrAny() throws UnknownHostException + { + return new byte[] {0, 0, 0, 0}; + } + + /** + * This method returns the hostname for a given IP address. It will + * throw an UnknownHostException if the hostname cannot be determined. + * + * @param ip The IP address as a byte array + * + * @return The hostname + * + * @exception UnknownHostException If the reverse lookup fails + */ + public static String getHostByAddr(byte[] ip) throws UnknownHostException + { + InetAddress addr = InetAddress.getByAddress(ip); + InetAddress.lookup(null, addr, false); + return addr.getHostName(); + } + + /** + * Returns a list of all IP addresses for a given hostname. Will throw + * an UnknownHostException if the hostname cannot be resolved. + */ + public static byte[][] getHostByName(String hostname) + throws UnknownHostException + { + InetAddress[] iaddrs = InetAddress.lookup(hostname, null, true); + byte[][] addrs = new byte[iaddrs.length][]; + for (int i = 0; i < iaddrs.length; i++) + addrs[i] = iaddrs[i].getAddress(); + return addrs; + } + + /** + * Return the IP address represented by a literal address. + * Will return null if the literal address is not valid. + * + * @param address the name of the host + * + * @return The IP address as a byte array + */ + public static byte[] aton(String address) + { + return InetAddress.aton(address); + } +} diff --git a/gcc-4.2.1/libjava/java/net/VMNetworkInterface.java b/gcc-4.2.1/libjava/java/net/VMNetworkInterface.java new file mode 100644 index 000000000..af71ce294 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/VMNetworkInterface.java @@ -0,0 +1,66 @@ +/* VMNetworkInterface.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.net; + +import gnu.classpath.Configuration; + +import java.util.Enumeration; +import java.util.Vector; + +/** + * This class models a network interface on the host computer. A network + * interface contains a name (typically associated with a specific + * hardware adapter) and a list of addresses that are bound to it. + * For example, an ethernet interface may be named "eth0" and have the + * address 192.168.1.101 assigned to it. + * + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + */ +final class VMNetworkInterface +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + System.loadLibrary("javanet"); + } + + public static native Vector getInterfaces() + throws SocketException; +} diff --git a/gcc-4.2.1/libjava/java/net/VMURLConnection.java b/gcc-4.2.1/libjava/java/net/VMURLConnection.java new file mode 100644 index 000000000..6555e8cba --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/VMURLConnection.java @@ -0,0 +1,76 @@ +/* VMURLConnection - VM code for URLConnection + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.net; + +import gnu.classpath.Configuration; + +import java.io.IOException; +import java.io.InputStream; + +final class VMURLConnection +{ + public static final int LENGTH = 1024; + + // private static native void init(); + + private static String guessContentTypeFromBuffer(byte[] b, int valid) + { + // FIXME - write real implementation + return null; + } + + /** + * This is called from URLConnection to guess the mime type of a + * stream. This method may return null to indicate that it could + * not guess a type. + */ + static String guessContentTypeFromStream(InputStream is) + throws IOException + { + if (! is.markSupported()) + return null; + is.mark(LENGTH); + byte[] bytes = new byte[LENGTH]; + int r = is.read(bytes); + if (r < 0) + return null; + is.reset(); + return guessContentTypeFromBuffer(bytes, r); + } +} diff --git a/gcc-4.2.1/libjava/java/net/natInetAddressNoNet.cc b/gcc-4.2.1/libjava/java/net/natInetAddressNoNet.cc new file mode 100644 index 000000000..0374af18f --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natInetAddressNoNet.cc @@ -0,0 +1,36 @@ +/* Copyright (C) 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <stddef.h> + +#include <java/net/InetAddress.h> + +jbyteArray +java::net::InetAddress::aton (jstring) +{ + return NULL; +} + +jint +java::net::InetAddress::getFamily (jbyteArray bytes) +{ + return 0; +} + +JArray<java::net::InetAddress*> * +java::net::InetAddress::lookup (jstring, java::net::InetAddress *, jboolean) +{ + return NULL; +} + +jstring +java::net::InetAddress::getLocalHostname () +{ + return NULL; +} diff --git a/gcc-4.2.1/libjava/java/net/natInetAddressPosix.cc b/gcc-4.2.1/libjava/java/net/natInetAddressPosix.cc new file mode 100644 index 000000000..d343f2332 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natInetAddressPosix.cc @@ -0,0 +1,304 @@ +/* Copyright (C) 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <string.h> +#include <errno.h> + +#include <sys/param.h> +#include <sys/types.h> +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/net/InetAddress.h> +#include <java/net/UnknownHostException.h> +#include <java/lang/SecurityException.h> + +#if defined(HAVE_UNAME) && ! defined(HAVE_GETHOSTNAME) +#include <sys/utsname.h> +#endif + +#ifndef HAVE_GETHOSTNAME_DECL +extern "C" int gethostname (char *name, int namelen); +#endif + +jbyteArray +java::net::InetAddress::aton (jstring host) +{ + char *hostname; + char buf[100]; + int len = JvGetStringUTFLength(host); + if (len < 100) + hostname = buf; + else + hostname = (char*) _Jv_AllocBytes (len+1); + JvGetStringUTFRegion (host, 0, host->length(), hostname); + buf[len] = '\0'; + char* bytes = NULL; + int blen = 0; +#ifdef HAVE_INET_ATON + struct in_addr laddr; + if (inet_aton (hostname, &laddr)) + { + bytes = (char*) &laddr; + blen = 4; + } +#elif defined(HAVE_INET_ADDR) +#if ! HAVE_IN_ADDR_T + typedef jint in_addr_t; +#endif + in_addr_t laddr = inet_addr (hostname); + if (laddr != (in_addr_t)(-1)) + { + bytes = (char*) &laddr; + blen = 4; + } +#endif +#if defined (HAVE_INET_PTON) && defined (HAVE_INET6) + char inet6_addr[16]; + if (len != 0 && inet_pton (AF_INET6, hostname, inet6_addr) > 0) + { + bytes = inet6_addr; + blen = 16; + } +#endif + if (blen == 0) + return NULL; + jbyteArray result = JvNewByteArray (blen); + memcpy (elements (result), bytes, blen); + return result; +} + +jint +java::net::InetAddress::getFamily (jbyteArray bytes) +{ + int len = bytes->length; + if (len == 4) + return AF_INET; +#ifdef HAVE_INET6 + else if (len == 16) + return AF_INET6; +#endif /* HAVE_INET6 */ + else + JvFail ("unrecognized size"); +} + + +JArray<java::net::InetAddress*> * +java::net::InetAddress::lookup (jstring host, java::net::InetAddress* iaddr, + jboolean all) +{ + struct hostent *hptr = NULL; +#if defined (HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYADDR_R) + struct hostent hent_r; +#if HAVE_STRUCT_HOSTENT_DATA + struct hostent_data fixed_buffer, *buffer_r = &fixed_buffer; +#else +#if defined (__GLIBC__) + // FIXME: in glibc, gethostbyname_r returns NETDB_INTERNAL to herr and + // ERANGE to errno if the buffer size is too small, rather than what is + // expected here. We work around this by setting a bigger buffer size and + // hoping that it is big enough. + char fixed_buffer[1024]; +#else + char fixed_buffer[200]; +#endif + char *buffer_r = fixed_buffer; + int size_r = sizeof (fixed_buffer); +#endif +#endif + + if (host != NULL) + { + char *hostname; + char buf[100]; + int len = JvGetStringUTFLength(host); + if (len < 100) + hostname = buf; + else + hostname = (char*) _Jv_AllocBytes (len+1); + JvGetStringUTFRegion (host, 0, host->length(), hostname); + buf[len] = '\0'; +#ifdef HAVE_GETHOSTBYNAME_R + while (true) + { + int ok; +#if HAVE_STRUCT_HOSTENT_DATA + ok = ! gethostbyname_r (hostname, &hent_r, buffer_r); +#else + int herr = 0; +#ifdef GETHOSTBYNAME_R_RETURNS_INT + ok = ! gethostbyname_r (hostname, &hent_r, buffer_r, size_r, + &hptr, &herr); +#else + hptr = gethostbyname_r (hostname, &hent_r, buffer_r, size_r, &herr); + ok = hptr != NULL; +#endif /* GETHOSTNAME_R_RETURNS_INT */ + if (! ok && herr == ERANGE) + { + size_r *= 2; + buffer_r = (char *) _Jv_AllocBytes (size_r); + } + else +#endif /* HAVE_STRUCT_HOSTENT_DATA */ + break; + } +#else + // FIXME: this is insufficient if some other piece of code calls + // this gethostbyname. + JvSynchronize sync (java::net::InetAddress::loopbackAddress); + hptr = gethostbyname (hostname); +#endif /* HAVE_GETHOSTBYNAME_R */ + } + else + { + jbyteArray bytes = iaddr->addr; + char *chars = (char*) elements (bytes); + int len = bytes->length; + int type; + char *val; + if (len == 4) + { + val = chars; + type = iaddr->family = AF_INET; + } +#ifdef HAVE_INET6 + else if (len == 16) + { + val = (char *) &chars; + type = iaddr->family = AF_INET6; + } +#endif /* HAVE_INET6 */ + else + JvFail ("unrecognized size"); + +#ifdef HAVE_GETHOSTBYADDR_R + while (true) + { + int ok; +#if HAVE_STRUCT_HOSTENT_DATA + ok = ! gethostbyaddr_r (val, len, type, &hent_r, buffer_r); +#else + int herr = 0; +#ifdef GETHOSTBYADDR_R_RETURNS_INT + ok = ! gethostbyaddr_r (val, len, type, &hent_r, + buffer_r, size_r, &hptr, &herr); +#else + hptr = gethostbyaddr_r (val, len, type, &hent_r, + buffer_r, size_r, &herr); + ok = hptr != NULL; +#endif /* GETHOSTBYADDR_R_RETURNS_INT */ + if (! ok && herr == ERANGE) + { + size_r *= 2; + buffer_r = (char *) _Jv_AllocBytes (size_r); + } + else +#endif /* HAVE_STRUCT_HOSTENT_DATA */ + break; + } +#else /* HAVE_GETHOSTBYADDR_R */ + // FIXME: this is insufficient if some other piece of code calls + // this gethostbyaddr. + JvSynchronize sync (java::net::InetAddress::loopbackAddress); + hptr = gethostbyaddr (val, len, type); +#endif /* HAVE_GETHOSTBYADDR_R */ + } + if (hptr != NULL) + { + if (!all) + host = JvNewStringUTF (hptr->h_name); + } + if (hptr == NULL) + { + if (iaddr != NULL && iaddr->addr != NULL) + { + iaddr->hostName = iaddr->getHostAddress(); + return NULL; + } + else + throw new java::net::UnknownHostException(host); + } + int count; + if (all) + { + char** ptr = hptr->h_addr_list; + count = 0; + while (*ptr++) count++; + } + else + count = 1; + JArray<java::net::InetAddress*> *result; + java::net::InetAddress** iaddrs; + if (all) + { + result = java::net::InetAddress::allocArray (count); + iaddrs = elements (result); + } + else + { + result = NULL; + iaddrs = &iaddr; + } + + for (int i = 0; i < count; i++) + { + if (iaddrs[i] == NULL) + iaddrs[i] = new java::net::InetAddress (NULL, NULL); + if (iaddrs[i]->hostName == NULL) + iaddrs[i]->hostName = host; + if (iaddrs[i]->addr == NULL) + { + char *bytes = hptr->h_addr_list[i]; + iaddrs[i]->addr = JvNewByteArray (hptr->h_length); + iaddrs[i]->family = getFamily (iaddrs[i]->addr); + memcpy (elements (iaddrs[i]->addr), bytes, hptr->h_length); + } + } + return result; +} + +jstring +java::net::InetAddress::getLocalHostname () +{ + char *chars; +#ifdef HAVE_GETHOSTNAME + char buffer[MAXHOSTNAMELEN]; + if (gethostname (buffer, MAXHOSTNAMELEN)) + return NULL; + chars = buffer; +#elif HAVE_UNAME + struct utsname stuff; + if (uname (&stuff) != 0) + return NULL; + chars = stuff.nodename; +#else + return NULL; +#endif + // It is admittedly non-optimal to convert the hostname to Unicode + // only to convert it back in getByName, but simplicity wins. Note + // that unless there is a SecurityManager, we only get called once + // anyway, thanks to the InetAddress.localhost cache. + return JvNewStringUTF (chars); +} diff --git a/gcc-4.2.1/libjava/java/net/natInetAddressWin32.cc b/gcc-4.2.1/libjava/java/net/natInetAddressWin32.cc new file mode 100644 index 000000000..82c1e6f70 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natInetAddressWin32.cc @@ -0,0 +1,168 @@ +/* Copyright (C) 2003 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#undef STRICT + +#include <java/net/InetAddress.h> +#include <java/net/UnknownHostException.h> +#include <java/lang/SecurityException.h> + +jbyteArray +java::net::InetAddress::aton (jstring host) +{ + JV_TEMP_UTF_STRING (hostname, host); + char* bytes = NULL; + int blen = 0; + unsigned long laddr = inet_addr (hostname); + if (laddr != INADDR_NONE) + { + bytes = (char*) &laddr; + blen = 4; + } + if (blen == 0) + return NULL; + jbyteArray result = JvNewByteArray (blen); + memcpy (elements (result), bytes, blen); + return result; +} + +jint +java::net::InetAddress::getFamily (jbyteArray bytes) +{ + int len = bytes->length; + if (len == 4) + return AF_INET; +#ifdef HAVE_INET6 + else if (len == 16) + return AF_INET6; +#endif /* HAVE_INET6 */ + else + JvFail ("unrecognized size"); +} + + +JArray<java::net::InetAddress*> * +java::net::InetAddress::lookup (jstring host, java::net::InetAddress* iaddr, + jboolean all) +{ + struct hostent *hptr = NULL; + if (host != NULL) + { + JV_TEMP_UTF_STRING (hostname, host); + + // FIXME: this is insufficient if some other piece of code calls + // this gethostbyname. + JvSynchronize sync (java::net::InetAddress::loopbackAddress); + hptr = gethostbyname (hostname); + } + else + { + jbyteArray bytes = iaddr->addr; + char *chars = (char*) elements (bytes); + int len = bytes->length; + int type; + char *val; + if (len == 4) + { + val = chars; + type = iaddr->family = AF_INET; + } +#ifdef HAVE_INET6 + else if (len == 16) + { + val = (char *) &chars; + type = iaddr->family = AF_INET6; + } +#endif /* HAVE_INET6 */ + else + JvFail ("unrecognized size"); + + // FIXME: this is insufficient if some other piece of code calls + // this gethostbyaddr. + JvSynchronize sync (java::net::InetAddress::loopbackAddress); + hptr = gethostbyaddr (val, len, type); + } + if (hptr != NULL) + { + if (!all) + host = JvNewStringUTF (hptr->h_name); + java::lang::SecurityException *ex = checkConnect (host); + if (ex != NULL) + { + if (iaddr == NULL || iaddr->addr == NULL) + throw ex; + hptr = NULL; + } + } + if (hptr == NULL) + { + if (iaddr != NULL && iaddr->addr != NULL) + { + iaddr->hostName = iaddr->getHostAddress(); + return NULL; + } + else + throw new java::net::UnknownHostException(host); + } + + int count; + if (all) + { + char** ptr = hptr->h_addr_list; + count = 0; + while (*ptr++) count++; + } + else + count = 1; + + JArray<java::net::InetAddress*> *result; + java::net::InetAddress** iaddrs; + if (all) + { + result = java::net::InetAddress::allocArray (count); + iaddrs = elements (result); + } + else + { + result = NULL; + iaddrs = &iaddr; + } + + for (int i = 0; i < count; i++) + { + if (iaddrs[i] == NULL) + iaddrs[i] = new java::net::InetAddress (NULL, NULL); + if (iaddrs[i]->hostName == NULL) + iaddrs[i]->hostName = host; + if (iaddrs[i]->addr == NULL) + { + char *bytes = hptr->h_addr_list[i]; + iaddrs[i]->addr = JvNewByteArray (hptr->h_length); + iaddrs[i]->family = getFamily (iaddrs[i]->addr); + memcpy (elements (iaddrs[i]->addr), bytes, hptr->h_length); + } + } + + return result; +} + +jstring +java::net::InetAddress::getLocalHostname () +{ + char buffer[400]; + if (gethostname (buffer, sizeof(buffer))) + return NULL; + // It is admittedly non-optimal to convert the hostname to Unicode + // only to convert it back in getByName, but simplicity wins. Note + // that unless there is a SecurityManager, we only get called once + // anyway, thanks to the InetAddress.localhost cache. + return JvNewStringUTF (buffer); +} diff --git a/gcc-4.2.1/libjava/java/net/natURLClassLoader.cc b/gcc-4.2.1/libjava/java/net/natURLClassLoader.cc new file mode 100644 index 000000000..ead0db44a --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natURLClassLoader.cc @@ -0,0 +1,22 @@ +// natURLClassLoader.cc -- Native part of the URLClassLoader class. + +/* Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/net/URLClassLoader.h> + +jboolean +java::net::URLClassLoader::runtimeInitialized () +{ + return gcj::runtimeInitialized; +} diff --git a/gcc-4.2.1/libjava/java/net/natVMNetworkInterfaceNoNet.cc b/gcc-4.2.1/libjava/java/net/natVMNetworkInterfaceNoNet.cc new file mode 100644 index 000000000..eda7f99f0 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natVMNetworkInterfaceNoNet.cc @@ -0,0 +1,21 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <java/net/SocketException.h> +#include <java/net/VMNetworkInterface.h> +#include <java/util/Vector.h> + +::java::util::Vector* +java::net::VMNetworkInterface::getInterfaces () +{ + throw new SocketException ( + JvNewStringLatin1 ("VMNetworkInterface.getInterfaces: unimplemented")); +} diff --git a/gcc-4.2.1/libjava/java/net/natVMNetworkInterfacePosix.cc b/gcc-4.2.1/libjava/java/net/natVMNetworkInterfacePosix.cc new file mode 100644 index 000000000..bfb11d21c --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natVMNetworkInterfacePosix.cc @@ -0,0 +1,163 @@ +/* Copyright (C) 2003, 2005, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +#include <sys/param.h> +#include <sys/types.h> +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#define BSD_COMP /* Get FIONREAD on Solaris2. */ +#include <sys/ioctl.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif + +#include <gcj/cni.h> +#include <jvm.h> +#include <java/net/InetAddress.h> +#include <java/net/NetworkInterface.h> +#include <java/net/SocketException.h> +#include <java/net/VMNetworkInterface.h> +#include <java/util/Vector.h> + +::java::util::Vector* +java::net::VMNetworkInterface::getInterfaces () +{ + ::java::util::Vector* ht = new ::java::util::Vector (); + +#ifdef HAVE_GETIFADDRS + + struct ifaddrs *addrs; + if (::getifaddrs (&addrs) == -1) + throw new ::java::net::SocketException(JvNewStringUTF (strerror (errno))); + + for (struct ifaddrs *work = addrs; work != NULL; work = work->ifa_next) + { + // Sometimes the address can be NULL; I don't know why but + // there's nothing we can do with this. + if (! work->ifa_addr) + continue; + // We only return Inet4 or Inet6 addresses. + jbyteArray laddr; + if (work->ifa_addr->sa_family == AF_INET) + { + sockaddr_in *real = reinterpret_cast<sockaddr_in *> (work->ifa_addr); + laddr = JvNewByteArray(4); + memcpy (elements (laddr), &real->sin_addr, 4); + } +#ifdef HAVE_INET6 + else if (work->ifa_addr->sa_family == AF_INET6) + { + sockaddr_in6 *real + = reinterpret_cast<sockaddr_in6 *> (work->ifa_addr); + laddr = JvNewByteArray(16); + memcpy (elements (laddr), &real->sin6_addr, 16); + } +#endif + else + continue; + + ::java::net::InetAddress *inaddr + = ::java::net::InetAddress::getByAddress(laddr); + + // It is ok to make a new NetworkInterface for each struct; the + // java code will unify these as necessary; see + // NetworkInterface.condense(). + jstring name = JvNewStringUTF (work->ifa_name); + + ht->add (new NetworkInterface (name, inaddr)); + } + + freeifaddrs (addrs); + +#else /* ! HAVE_GETIFADDRS */ + + int fd; + int num_interfaces = 0; + struct ifconf if_data; + struct ifreq* if_record; + + if_data.ifc_len = 0; + if_data.ifc_buf = NULL; + + // Open a (random) socket to have a file descriptor for the ioctl calls. + fd = _Jv_socket (PF_INET, SOCK_DGRAM, htons (IPPROTO_IP)); + + if (fd < 0) + throw new ::java::net::SocketException; + + // Get all interfaces. If not enough buffers are available try it + // with a bigger buffer size. + do + { + num_interfaces += 16; + + if_data.ifc_len = sizeof (struct ifreq) * num_interfaces; + if_data.ifc_buf = + (char*) _Jv_Realloc (if_data.ifc_buf, if_data.ifc_len); + + // Try to get all local interfaces. + if (::ioctl (fd, SIOCGIFCONF, &if_data) < 0) + throw new java::net::SocketException; + } + while (if_data.ifc_len >= (int) (sizeof (struct ifreq) * num_interfaces)); + + // Get addresses of all interfaces. + if_record = if_data.ifc_req; + + for (int n = 0; n < if_data.ifc_len; n += sizeof (struct ifreq)) + { + struct ifreq ifr; + + memset (&ifr, 0, sizeof (ifr)); + strcpy (ifr.ifr_name, if_record->ifr_name); + + // Try to get the IPv4-address of the local interface + if (::ioctl (fd, SIOCGIFADDR, &ifr) < 0) + throw new java::net::SocketException; + + int len = 4; + struct sockaddr_in sa = *((sockaddr_in*) &(ifr.ifr_addr)); + + jbyteArray baddr = JvNewByteArray (len); + memcpy (elements (baddr), &(sa.sin_addr), len); + jstring if_name = JvNewStringLatin1 (if_record->ifr_name); + InetAddress* address = java::net::InetAddress::getByAddress (baddr); + ht->add (new NetworkInterface (if_name, address)); + if_record++; + } + + _Jv_Free (if_data.ifc_buf); + + if (fd >= 0) + _Jv_close (fd); +#endif /* HAVE_GETIFADDRS */ + + return ht; +} diff --git a/gcc-4.2.1/libjava/java/net/natVMNetworkInterfaceWin32.cc b/gcc-4.2.1/libjava/java/net/natVMNetworkInterfaceWin32.cc new file mode 100644 index 000000000..d42f33de9 --- /dev/null +++ b/gcc-4.2.1/libjava/java/net/natVMNetworkInterfaceWin32.cc @@ -0,0 +1,144 @@ +/* Copyright (C) 2003, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#undef STRICT + +#include <java/net/NetworkInterface.h> +#include <java/net/Inet4Address.h> +#include <java/net/SocketException.h> +#include <java/net/VMNetworkInterface.h> +#include <java/util/Vector.h> + +/* As of this writing, NetworkInterface.java has + getName() == getDisplayName() and only one IP address + per interface. If this changes, we'll need to use + iphlpapi (not supported on Win95) to retrieve richer + adapter information via GetAdaptersInfo(). In this + module, we provide the necessary hooks to detect the + presence of iphlpapi and use it if necessary, but + comment things out for now to avoid compiler warnings. */ + +enum {MAX_INTERFACES = 50}; + +typedef int +(*PfnGetRealNetworkInterfaces) (jstring* pjstrName, + java::net::InetAddress** ppAddress); + +static int +winsock2GetRealNetworkInterfaces (jstring* pjstrName, + java::net::InetAddress** ppAddress) +{ + // FIXME: Add IPv6 support. + + INTERFACE_INFO arInterfaceInfo[MAX_INTERFACES]; + + // Open a (random) socket to have a file descriptor for the WSAIoctl call. + SOCKET skt = ::socket (AF_INET, SOCK_DGRAM, 0); + if (skt == INVALID_SOCKET) + _Jv_ThrowSocketException (); + + DWORD dwOutBufSize; + int nRetCode = ::WSAIoctl (skt, SIO_GET_INTERFACE_LIST, + NULL, 0, &arInterfaceInfo, sizeof(arInterfaceInfo), + &dwOutBufSize, NULL, NULL); + + if (nRetCode == SOCKET_ERROR) + { + DWORD dwLastErrorCode = WSAGetLastError (); + ::closesocket (skt); + _Jv_ThrowSocketException (dwLastErrorCode); + } + + // Get addresses of all interfaces. + int nNbInterfaces = dwOutBufSize / sizeof(INTERFACE_INFO); + int nCurETHInterface = 0; + for (int i=0; i < nNbInterfaces; ++i) + { + int len = 4; + jbyteArray baddr = JvNewByteArray (len); + SOCKADDR_IN* pAddr = (SOCKADDR_IN*) &arInterfaceInfo[i].iiAddress; + memcpy (elements (baddr), &(pAddr->sin_addr), len); + + // Concoct a name for this interface. Since we don't + // have access to the real name under Winsock 2, we use + // "lo" for the loopback interface and ethX for the + // real ones. + TCHAR szName[30]; + u_long lFlags = arInterfaceInfo[i].iiFlags; + + if (lFlags & IFF_LOOPBACK) + _tcscpy (szName, _T("lo")); + else + { + _tcscpy (szName, _T("eth")); + wsprintf(szName+3, _T("%d"), nCurETHInterface++); + } + + jstring if_name = _Jv_Win32NewString (szName); + java::net::Inet4Address* address = + new java::net::Inet4Address (baddr, JvNewStringLatin1 ("")); + pjstrName[i] = if_name; + ppAddress[i] = address; + } + + ::closesocket (skt); + + return nNbInterfaces; +} + +/* +static int +iphlpapiGetRealNetworkInterfaces (jstring* pjstrName, + java::net::InetAddress** ppAddress) +{ + return 0; +} +*/ + +static PfnGetRealNetworkInterfaces +determineGetRealNetworkInterfacesFN () +{ + /* FIXME: Try to dynamically load iphlpapi.dll and + detect the presence of GetAdaptersInfo() using + GetProcAddress(). If successful, return + iphlpapiGetRealNetworkInterfaces; if not, + return winsock2GetRealNetworkInterfaces */ + return &winsock2GetRealNetworkInterfaces; +} + +::java::util::Vector* +java::net::VMNetworkInterface::getInterfaces () +{ + // This next declaration used to be a static local, + // but this introduced a dependency on libsupc++ due + // to _cxa_guard_acquire and _cxa_guard_release. + // When Win95 is gone and we eventually get rid of + // winsock2GetRealNetworkInterfaces, we can rework + // all of this. Alternatively, we could move this all + // to win32.cc and initialize this at startup time, + // but that seems more trouble than it's worth at + // the moment. + PfnGetRealNetworkInterfaces pfn = + determineGetRealNetworkInterfacesFN (); + + jstring arIFName[MAX_INTERFACES]; + InetAddress* arpInetAddress[MAX_INTERFACES]; + ::java::util::Vector* ht = new ::java::util::Vector (); + + int nNbInterfaces = (*pfn) (arIFName, arpInetAddress); + for (int i=0; i < nNbInterfaces; ++i) + { + ht->add (new java::net::NetworkInterface (arIFName[i], + arpInetAddress[i])); + } + + return ht; +} diff --git a/gcc-4.2.1/libjava/java/nio/Buffer.java b/gcc-4.2.1/libjava/java/nio/Buffer.java new file mode 100644 index 000000000..f369b9622 --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/Buffer.java @@ -0,0 +1,361 @@ +/* Buffer.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +import gnu.gcj.RawData; + +/** + * @since 1.4 + */ +public abstract class Buffer +{ + int cap = 0; + int limit = 0; + int pos = 0; + int mark = -1; + RawData address; + + /** + * Creates a new Buffer. + * + * Should be package private. + */ + Buffer (int capacity, int limit, int position, int mark) + { + if (capacity < 0) + throw new IllegalArgumentException (); + + cap = capacity; + limit (limit); + position (position); + + if (mark >= 0) + { + if (mark > pos) + throw new IllegalArgumentException (); + + this.mark = mark; + } + } + + /** + * Retrieves the capacity of the buffer. + * + * @return the capacity of the buffer + */ + public final int capacity () + { + return cap; + } + + /** + * Clears the buffer. + * + * @return this buffer + */ + public final Buffer clear () + { + limit = cap; + pos = 0; + mark = -1; + return this; + } + + /** + * Flips the buffer. + * + * @return this buffer + */ + public final Buffer flip () + { + limit = pos; + pos = 0; + mark = -1; + return this; + } + + /** + * Tells whether the buffer has remaining data to read or not. + * + * @return true if the buffer contains remaining data to read, + * false otherwise + */ + public final boolean hasRemaining () + { + return remaining() > 0; + } + + /** + * Tells whether this buffer is read only or not. + * + * @return true if the buffer is read only, false otherwise + */ + public abstract boolean isReadOnly (); + + /** + * Retrieves the current limit of the buffer. + * + * @return the limit of the buffer + */ + public final int limit () + { + return limit; + } + + /** + * Sets this buffer's limit. + * + * @param newLimit The new limit value; must be non-negative and no larger + * than this buffer's capacity. + * + * @return this buffer + * + * @exception IllegalArgumentException If the preconditions on newLimit + * do not hold. + */ + public final Buffer limit (int newLimit) + { + if ((newLimit < 0) || (newLimit > cap)) + throw new IllegalArgumentException (); + + if (newLimit < mark) + mark = -1; + + if (pos > newLimit) + pos = newLimit; + + limit = newLimit; + return this; + } + + /** + * Sets this buffer's mark at its position. + * + * @return this buffer + */ + public final Buffer mark () + { + mark = pos; + return this; + } + + /** + * Retrieves the current position of this buffer. + * + * @return the current position of this buffer + */ + public final int position () + { + return pos; + } + + /** + * Sets this buffer's position. If the mark is defined and larger than the + * new position then it is discarded. + * + * @param newPosition The new position value; must be non-negative and no + * larger than the current limit. + * + * @return this buffer + * + * @exception IllegalArgumentException If the preconditions on newPosition + * do not hold + */ + public final Buffer position (int newPosition) + { + if ((newPosition < 0) || (newPosition > limit)) + throw new IllegalArgumentException (); + + if (newPosition <= mark) + mark = -1; + + pos = newPosition; + return this; + } + + /** + * Returns the number of elements between the current position and the limit. + * + * @return the number of remaining elements + */ + public final int remaining() + { + return limit - pos; + } + + /** + * Resets this buffer's position to the previously-marked position. + * + * @return this buffer + * + * @exception InvalidMarkException If the mark has not been set. + */ + public final Buffer reset() + { + if (mark == -1) + throw new InvalidMarkException (); + + pos = mark; + return this; + } + + /** + * Rewinds this buffer. The position is set to zero and the mark + * is discarded. + * + * @return this buffer + */ + public final Buffer rewind() + { + pos = 0; + mark = -1; + return this; + } + + /** + * Checks for underflow. This method is used internally to check + * whether a buffer has enough elements left to satisfy a read + * request. + * + * @exception BufferUnderflowException If there are no remaining + * elements in this buffer. + */ + final void checkForUnderflow() + { + if (!hasRemaining()) + throw new BufferUnderflowException(); + } + + /** + * Checks for underflow. This method is used internally to check + * whether a buffer has enough elements left to satisfy a read + * request for a given number of elements. + * + * @param length The length of a sequence of elements. + * + * @exception BufferUnderflowException If there are not enough + * remaining elements in this buffer. + */ + final void checkForUnderflow(int length) + { + if (remaining() < length) + throw new BufferUnderflowException(); + } + + /** + * Checks for overflow. This method is used internally to check + * whether a buffer has enough space left to satisfy a write + * request. + * + * @exception BufferOverflowException If there is no remaining + * space in this buffer. + */ + final void checkForOverflow() + { + if (!hasRemaining()) + throw new BufferOverflowException(); + } + + /** + * Checks for overflow. This method is used internally to check + * whether a buffer has enough space left to satisfy a write + * request for a given number of elements. + * + * @param length The length of a sequence of elements. + * + * @exception BufferUnderflowException If there is not enough + * remaining space in this buffer. + */ + final void checkForOverflow(int length) + { + if (remaining() < length) + throw new BufferOverflowException(); + } + + /** + * Checks if index is negative or not smaller than the buffer's + * limit. This method is used internally to check whether + * an indexed request can be fulfilled. + * + * @param index The requested position in the buffer. + * + * @exception IndexOutOfBoundsException If index is negative or not smaller + * than the buffer's limit. + */ + final void checkIndex(int index) + { + if (index < 0 + || index >= limit ()) + throw new IndexOutOfBoundsException (); + } + + /** + * Checks if buffer is read-only. This method is used internally to + * check if elements can be put into a buffer. + * + * @exception ReadOnlyBufferException If this buffer is read-only. + */ + final void checkIfReadOnly() + { + if (isReadOnly()) + throw new ReadOnlyBufferException (); + } + + /** + * Checks whether an array is large enough to hold the given number of + * elements at the given offset. This method is used internally to + * check if an array is big enough. + * + * @param arraylength The length of the array. + * @param offset The offset within the array of the first byte to be read; + * must be non-negative and no larger than arraylength. + * @param length The number of bytes to be read from the given array; + * must be non-negative and no larger than arraylength - offset. + * + * @exception IndexOutOfBoundsException If the preconditions on the offset + * and length parameters do not hold + */ + static final void checkArraySize(int arraylength, int offset, int length) + { + if ((offset < 0) || + (length < 0) || + (arraylength < length + offset)) + throw new IndexOutOfBoundsException (); + } +} diff --git a/gcc-4.2.1/libjava/java/nio/DirectByteBufferImpl.java b/gcc-4.2.1/libjava/java/nio/DirectByteBufferImpl.java new file mode 100644 index 000000000..e448ea97c --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/DirectByteBufferImpl.java @@ -0,0 +1,431 @@ +/* DirectByteBufferImpl.java -- + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +import gnu.gcj.RawData; + +abstract class DirectByteBufferImpl extends ByteBuffer +{ + /** + * The owner is used to keep alive the object that actually owns the + * memory. There are three possibilities: + * 1) owner == this: We allocated the memory and we should free it, + * but *only* in finalize (if we've been sliced + * other objects will also have access to the + * memory). + * 2) owner == null: The byte buffer was created thru + * JNI.NewDirectByteBuffer. The JNI code is + * responsible for freeing the memory. + * 3) owner == some other object: The other object allocated the + * memory and should free it. + */ + private final Object owner; + + static final class ReadOnly extends DirectByteBufferImpl + { + ReadOnly(Object owner, RawData address, + int capacity, int limit, + int position) + { + super(owner, address, capacity, limit, position); + } + + public ByteBuffer put(byte value) + { + throw new ReadOnlyBufferException (); + } + + public ByteBuffer put(int index, byte value) + { + throw new ReadOnlyBufferException (); + } + + public boolean isReadOnly() + { + return true; + } + } + + static final class ReadWrite extends DirectByteBufferImpl + { + ReadWrite(int capacity) + { + super(capacity); + } + + ReadWrite(RawData address, int capacity) + { + super(address, capacity); + } + + ReadWrite(Object owner, RawData address, + int capacity, int limit, + int position) + { + super(owner, address, capacity, limit, position); + } + + public boolean isReadOnly() + { + return false; + } + } + + DirectByteBufferImpl(int capacity) + { + super(capacity, capacity, 0, -1); + this.owner = this; + this.address = VMDirectByteBuffer.allocate(capacity); + } + + DirectByteBufferImpl(RawData address, int capacity) + { + super(capacity, capacity, 0, -1); + this.owner = null; + this.address = address; + } + + DirectByteBufferImpl(Object owner, RawData address, + int capacity, int limit, + int position) + { + super(capacity, limit, position, -1); + this.owner = owner; + this.address = address; + } + + /** + * Allocates a new direct byte buffer. + */ + public static ByteBuffer allocate(int capacity) + { + return new DirectByteBufferImpl.ReadWrite(capacity); + } + + protected void finalize() throws Throwable + { + if (owner == this) + VMDirectByteBuffer.free(address); + } + + public byte get() + { + checkForUnderflow(); + + int pos = position(); + byte result = VMDirectByteBuffer.get(address, pos); + position(pos + 1); + return result; + } + + public byte get(int index) + { + checkIndex(index); + + return VMDirectByteBuffer.get(address, index); + } + + public ByteBuffer get(byte[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + int index = position(); + VMDirectByteBuffer.get(address, index, dst, offset, length); + position(index+length); + + return this; + } + + public ByteBuffer put(byte value) + { + checkForOverflow(); + + int pos = position(); + VMDirectByteBuffer.put(address, pos, value); + position(pos + 1); + return this; + } + + public ByteBuffer put(int index, byte value) + { + checkIndex(index); + + VMDirectByteBuffer.put(address, index, value); + return this; + } + + void shiftDown(int dst_offset, int src_offset, int count) + { + VMDirectByteBuffer.shiftDown(address, dst_offset, src_offset, count); + } + + public ByteBuffer compact() + { + checkIfReadOnly(); + mark = -1; + int pos = position(); + if (pos > 0) + { + int count = remaining(); + VMDirectByteBuffer.shiftDown(address, 0, pos, count); + position(count); + limit(capacity()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public ByteBuffer slice() + { + int rem = remaining(); + if (isReadOnly()) + return new DirectByteBufferImpl.ReadOnly + (owner, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + else + return new DirectByteBufferImpl.ReadWrite + (owner, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + } + + private ByteBuffer duplicate(boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + DirectByteBufferImpl result; + if (readOnly) + result = new DirectByteBufferImpl.ReadOnly(owner, address, capacity(), + limit(), pos); + else + result = new DirectByteBufferImpl.ReadWrite(owner, address, capacity(), + limit(), pos); + + if (mark != pos) + { + result.position(mark); + result.mark(); + result.position(pos); + } + return result; + } + + public ByteBuffer duplicate() + { + return duplicate(isReadOnly()); + } + + public ByteBuffer asReadOnlyBuffer() + { + return duplicate(true); + } + + public boolean isDirect() + { + return true; + } + + public CharBuffer asCharBuffer() + { + return new CharViewBufferImpl(this, remaining() >> 1); + } + + public ShortBuffer asShortBuffer() + { + return new ShortViewBufferImpl(this, remaining() >> 1); + } + + public IntBuffer asIntBuffer() + { + return new IntViewBufferImpl(this, remaining() >> 2); + } + + public LongBuffer asLongBuffer() + { + return new LongViewBufferImpl(this, remaining() >> 3); + } + + public FloatBuffer asFloatBuffer() + { + return new FloatViewBufferImpl(this, remaining() >> 2); + } + + public DoubleBuffer asDoubleBuffer() + { + return new DoubleViewBufferImpl(this, remaining() >> 3); + } + + public char getChar() + { + return ByteBufferHelper.getChar(this, order()); + } + + public ByteBuffer putChar(char value) + { + ByteBufferHelper.putChar(this, value, order()); + return this; + } + + public char getChar(int index) + { + return ByteBufferHelper.getChar(this, index, order()); + } + + public ByteBuffer putChar(int index, char value) + { + ByteBufferHelper.putChar(this, index, value, order()); + return this; + } + + public short getShort() + { + return ByteBufferHelper.getShort(this, order()); + } + + public ByteBuffer putShort(short value) + { + ByteBufferHelper.putShort(this, value, order()); + return this; + } + + public short getShort(int index) + { + return ByteBufferHelper.getShort(this, index, order()); + } + + public ByteBuffer putShort(int index, short value) + { + ByteBufferHelper.putShort(this, index, value, order()); + return this; + } + + public int getInt() + { + return ByteBufferHelper.getInt(this, order()); + } + + public ByteBuffer putInt(int value) + { + ByteBufferHelper.putInt(this, value, order()); + return this; + } + + public int getInt(int index) + { + return ByteBufferHelper.getInt(this, index, order()); + } + + public ByteBuffer putInt(int index, int value) + { + ByteBufferHelper.putInt(this, index, value, order()); + return this; + } + + public long getLong() + { + return ByteBufferHelper.getLong(this, order()); + } + + public ByteBuffer putLong(long value) + { + ByteBufferHelper.putLong(this, value, order()); + return this; + } + + public long getLong(int index) + { + return ByteBufferHelper.getLong(this, index, order()); + } + + public ByteBuffer putLong(int index, long value) + { + ByteBufferHelper.putLong(this, index, value, order()); + return this; + } + + public float getFloat() + { + return ByteBufferHelper.getFloat(this, order()); + } + + public ByteBuffer putFloat(float value) + { + ByteBufferHelper.putFloat(this, value, order()); + return this; + } + + public float getFloat(int index) + { + return ByteBufferHelper.getFloat(this, index, order()); + } + + public ByteBuffer putFloat(int index, float value) + { + ByteBufferHelper.putFloat(this, index, value, order()); + return this; + } + + public double getDouble() + { + return ByteBufferHelper.getDouble(this, order()); + } + + public ByteBuffer putDouble(double value) + { + ByteBufferHelper.putDouble(this, value, order()); + return this; + } + + public double getDouble(int index) + { + return ByteBufferHelper.getDouble(this, index, order()); + } + + public ByteBuffer putDouble(int index, double value) + { + ByteBufferHelper.putDouble(this, index, value, order()); + return this; + } +} diff --git a/gcc-4.2.1/libjava/java/nio/MappedByteBuffer.java b/gcc-4.2.1/libjava/java/nio/MappedByteBuffer.java new file mode 100644 index 000000000..9b6df1715 --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/MappedByteBuffer.java @@ -0,0 +1,89 @@ +/* MappedByteBuffer.java -- + Copyright (C) 2002, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +/** + * @author Michael Koch (konqueror@gmx.de) + * @since 1.4 + */ +public abstract class MappedByteBuffer extends ByteBuffer +{ + MappedByteBuffer (int capacity, int limit, int position, int mark) + { + super (capacity, limit, position, mark); + } + + void forceImpl() + { + } + + public final MappedByteBuffer force () + { + forceImpl(); + return this; + } + + boolean isLoadedImpl() + { + load(); + return true; + } + + public final boolean isLoaded () + { + return isLoadedImpl(); + } + + void loadImpl() + { + } + + public final MappedByteBuffer load () + { + loadImpl(); + return this; + } + + void unmapImpl () + { + forceImpl(); + } + + public void finalize () { unmapImpl(); } +} diff --git a/gcc-4.2.1/libjava/java/nio/MappedByteBufferImpl.java b/gcc-4.2.1/libjava/java/nio/MappedByteBufferImpl.java new file mode 100644 index 000000000..444eeea91 --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/MappedByteBufferImpl.java @@ -0,0 +1,360 @@ +/* MappedByteBufferImpl.java -- + Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +import gnu.gcj.RawData; + +import java.io.IOException; + +final class MappedByteBufferImpl extends MappedByteBuffer +{ + boolean readOnly; + + /** Posix uses this for the pointer returned by mmap; + * Win32 uses it for the pointer returned by MapViewOfFile. */ + public RawData implPtr; + /** Posix uses this for the actual length passed to mmap; + * Win32 uses it for the pointer returned by CreateFileMapping. */ + public long implLen; + + public MappedByteBufferImpl(RawData address, int size, boolean readOnly) + throws IOException + { + super(size, size, 0, -1); + this.address = address; + this.readOnly = readOnly; + } + + public boolean isReadOnly() + { + return readOnly; + } + + public byte get() + { + checkForUnderflow(); + + int pos = position(); + byte result = VMDirectByteBuffer.get(address, pos); + position(pos + 1); + return result; + } + + public ByteBuffer put(byte value) + { + checkIfReadOnly(); + checkForOverflow(); + + int pos = position(); + VMDirectByteBuffer.put(address, pos, value); + position(pos + 1); + return this; + } + + public byte get(int index) + { + checkIndex(index); + + return VMDirectByteBuffer.get(address, index); + } + + public ByteBuffer get(byte[] dst, int offset, int length) + { + checkArraySize(dst.length, offset, length); + checkForUnderflow(length); + + int index = position(); + VMDirectByteBuffer.get(address, index, dst, offset, length); + position(index+length); + + return this; + } + + public ByteBuffer put(int index, byte value) + { + checkIfReadOnly(); + checkIndex(index); + + VMDirectByteBuffer.put(address, index, value); + return this; + } + + public ByteBuffer compact() + { + checkIfReadOnly(); + mark = -1; + int pos = position(); + if (pos > 0) + { + int count = remaining(); + // Call shiftDown method optimized for direct buffers. + VMDirectByteBuffer.shiftDown(address, 0, pos, count); + position(count); + limit(capacity()); + } + else + { + position(limit()); + limit(capacity()); + } + return this; + } + + public boolean isDirect() + { + return true; + } + + public ByteBuffer slice() + { + int rem = remaining(); + if (isReadOnly()) + return new DirectByteBufferImpl.ReadOnly + (this, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + else + return new DirectByteBufferImpl.ReadWrite + (this, VMDirectByteBuffer.adjustAddress(address, position()), + rem, rem, 0); + } + + private ByteBuffer duplicate(boolean readOnly) + { + int pos = position(); + reset(); + int mark = position(); + position(pos); + DirectByteBufferImpl result; + if (readOnly) + result = new DirectByteBufferImpl.ReadOnly(this, address, capacity(), + limit(), pos); + else + result = new DirectByteBufferImpl.ReadWrite(this, address, capacity(), + limit(), pos); + + if (mark != pos) + { + result.position(mark); + result.mark(); + result.position(pos); + } + return result; + } + + public ByteBuffer duplicate() + { + return duplicate(isReadOnly()); + } + + public ByteBuffer asReadOnlyBuffer() + { + return duplicate(true); + } + + public CharBuffer asCharBuffer() + { + return new CharViewBufferImpl(this, remaining() >> 1); + } + + public ShortBuffer asShortBuffer() + { + return new ShortViewBufferImpl(this, remaining() >> 1); + } + + public IntBuffer asIntBuffer() + { + return new IntViewBufferImpl(this, remaining() >> 2); + } + + public LongBuffer asLongBuffer() + { + return new LongViewBufferImpl(this, remaining() >> 3); + } + + public FloatBuffer asFloatBuffer() + { + return new FloatViewBufferImpl(this, remaining() >> 2); + } + + public DoubleBuffer asDoubleBuffer() + { + return new DoubleViewBufferImpl(this, remaining() >> 3); + } + + public char getChar() + { + return ByteBufferHelper.getChar(this, order()); + } + + public ByteBuffer putChar(char value) + { + ByteBufferHelper.putChar(this, value, order()); + return this; + } + + public char getChar(int index) + { + return ByteBufferHelper.getChar(this, index, order()); + } + + public ByteBuffer putChar(int index, char value) + { + ByteBufferHelper.putChar(this, index, value, order()); + return this; + } + + public short getShort() + { + return ByteBufferHelper.getShort(this, order()); + } + + public ByteBuffer putShort(short value) + { + ByteBufferHelper.putShort(this, value, order()); + return this; + } + + public short getShort(int index) + { + return ByteBufferHelper.getShort(this, index, order()); + } + + public ByteBuffer putShort(int index, short value) + { + ByteBufferHelper.putShort(this, index, value, order()); + return this; + } + + public int getInt() + { + return ByteBufferHelper.getInt(this, order()); + } + + public ByteBuffer putInt(int value) + { + ByteBufferHelper.putInt(this, value, order()); + return this; + } + + public int getInt(int index) + { + return ByteBufferHelper.getInt(this, index, order()); + } + + public ByteBuffer putInt(int index, int value) + { + ByteBufferHelper.putInt(this, index, value, order()); + return this; + } + + public long getLong() + { + return ByteBufferHelper.getLong(this, order()); + } + + public ByteBuffer putLong(long value) + { + ByteBufferHelper.putLong(this, value, order()); + return this; + } + + public long getLong(int index) + { + return ByteBufferHelper.getLong(this, index, order()); + } + + public ByteBuffer putLong(int index, long value) + { + ByteBufferHelper.putLong(this, index, value, order()); + return this; + } + + public float getFloat() + { + return ByteBufferHelper.getFloat(this, order()); + } + + public ByteBuffer putFloat(float value) + { + ByteBufferHelper.putFloat(this, value, order()); + return this; + } + + public float getFloat(int index) + { + return ByteBufferHelper.getFloat(this, index, order()); + } + + public ByteBuffer putFloat(int index, float value) + { + ByteBufferHelper.putFloat(this, index, value, order()); + return this; + } + + public double getDouble() + { + return ByteBufferHelper.getDouble(this, order()); + } + + public ByteBuffer putDouble(double value) + { + ByteBufferHelper.putDouble(this, value, order()); + return this; + } + + public double getDouble(int index) + { + return ByteBufferHelper.getDouble(this, index, order()); + } + + public ByteBuffer putDouble(int index, double value) + { + ByteBufferHelper.putDouble(this, index, value, order()); + return this; + } + + // NOTE: In libgcj these methods are implemented in natFileChannelXxx.cc, + // because they're small, and to put them next to FileChannelImpl::mapImpl. + native void unmapImpl(); + native boolean isLoadedImpl(); + // FIXME: Try to load all pages into memory. + native void loadImpl(); + + native void forceImpl(); +} diff --git a/gcc-4.2.1/libjava/java/nio/VMDirectByteBuffer.java b/gcc-4.2.1/libjava/java/nio/VMDirectByteBuffer.java new file mode 100644 index 000000000..2aefaeb4b --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/VMDirectByteBuffer.java @@ -0,0 +1,53 @@ +/* VMDirectByteBuffer.java -- + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio; + +import gnu.classpath.Configuration; +import gnu.gcj.RawData; + +final class VMDirectByteBuffer +{ + static native RawData allocate (int capacity); + static native void free(RawData address); + static native byte get(RawData address, int index); + static native void get(RawData address, int index, byte[] dst, int offset, int length); + static native void put(RawData address, int index, byte value); + static native RawData adjustAddress(RawData address, int offset); + static native void shiftDown(RawData address, int dst_offset, int src_offset, int count); +} diff --git a/gcc-4.2.1/libjava/java/nio/channels/VMChannels.java b/gcc-4.2.1/libjava/java/nio/channels/VMChannels.java new file mode 100644 index 000000000..4f43a42ad --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/channels/VMChannels.java @@ -0,0 +1,85 @@ +/* VMChannels.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio.channels; + +import gnu.java.nio.ChannelInputStream; +import gnu.java.nio.ChannelOutputStream; +import gnu.java.nio.channels.FileChannelImpl; + +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +final class VMChannels +{ + /** + * This class isn't intended to be instantiated. + */ + private VMChannels() + { + // Do nothing here. + } + + static native FileInputStream newInputStream(FileChannelImpl ch); + + static native FileOutputStream newOutputStream(FileChannelImpl ch); + + /** + * Constructs a stream that reads bytes from the given channel. + */ + static InputStream newInputStream(ReadableByteChannel ch) + { + if (ch instanceof FileChannelImpl) + return newInputStream((FileChannelImpl) ch); + return new ChannelInputStream(ch); + } + + /** + * Constructs a stream that writes bytes to the given channel. + */ + static OutputStream newOutputStream(WritableByteChannel ch) + { + if (ch instanceof FileChannelImpl) + return newOutputStream((FileChannelImpl) ch); + return new ChannelOutputStream(ch); + } +} diff --git a/gcc-4.2.1/libjava/java/nio/channels/natVMChannels.cc b/gcc-4.2.1/libjava/java/nio/channels/natVMChannels.cc new file mode 100644 index 000000000..d40a51653 --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/channels/natVMChannels.cc @@ -0,0 +1,37 @@ +// natVMChannels.cc - Native part of VMChannels class. + +/* Copyright (C) 2004, 2006 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <gcj/cni.h> + +#include <java/nio/channels/VMChannels.h> +#include <java/nio/channels/Channels.h> +#include <java/io/FileInputStream.h> +#include <java/io/FileOutputStream.h> +#include <gnu/java/nio/channels/FileChannelImpl.h> + +using java::nio::channels::VMChannels; +using java::io::FileInputStream; +using java::io::FileOutputStream; +using gnu::java::nio::channels::FileChannelImpl; + +FileInputStream* +VMChannels::newInputStream(FileChannelImpl* ch) +{ + // Needs to be native to bypass Java access protection. + return new FileInputStream (ch); +} + +FileOutputStream* +VMChannels::newOutputStream(FileChannelImpl* ch) +{ + // Needs to be native to bypass Java access protection. + return new FileOutputStream (ch); +} diff --git a/gcc-4.2.1/libjava/java/nio/charset/Charset.java b/gcc-4.2.1/libjava/java/nio/charset/Charset.java new file mode 100644 index 000000000..48093bc9d --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/charset/Charset.java @@ -0,0 +1,412 @@ +/* Charset.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.nio.charset; + +import gnu.classpath.ServiceFactory; +import gnu.classpath.SystemProperties; +import gnu.java.nio.charset.Provider; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.spi.CharsetProvider; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Locale; +import java.util.Set; +import java.util.SortedMap; +import java.util.TreeMap; + +/** + * @author Jesse Rosenstock + * @since 1.4 + */ +public abstract class Charset implements Comparable +{ + private CharsetEncoder cachedEncoder; + private CharsetDecoder cachedDecoder; + + /** + * Charset providers. + */ + private static CharsetProvider[] providers; + + private final String canonicalName; + private final String[] aliases; + + protected Charset (String canonicalName, String[] aliases) + { + checkName (canonicalName); + if (aliases != null) + { + int n = aliases.length; + for (int i = 0; i < n; ++i) + checkName (aliases[i]); + } + + cachedEncoder = null; + cachedDecoder = null; + this.canonicalName = canonicalName; + this.aliases = aliases; + } + + /** + * @throws IllegalCharsetNameException if the name is illegal + */ + private static void checkName (String name) + { + int n = name.length (); + + if (n == 0) + throw new IllegalCharsetNameException (name); + + char ch = name.charAt (0); + if (!(('A' <= ch && ch <= 'Z') + || ('a' <= ch && ch <= 'z') + || ('0' <= ch && ch <= '9'))) + throw new IllegalCharsetNameException (name); + + for (int i = 1; i < n; ++i) + { + ch = name.charAt (i); + if (!(('A' <= ch && ch <= 'Z') + || ('a' <= ch && ch <= 'z') + || ('0' <= ch && ch <= '9') + || ch == '-' || ch == '.' || ch == ':' || ch == '_')) + throw new IllegalCharsetNameException (name); + } + } + + /** + * Returns the system default charset. + * + * This may be set by the user or VM with the file.encoding + * property. + * + * @since 1.5 + */ + public static Charset defaultCharset() + { + String encoding; + + try + { + encoding = SystemProperties.getProperty("file.encoding"); + } + catch(SecurityException e) + { + // Use fallback. + encoding = "ISO-8859-1"; + } + catch(IllegalArgumentException e) + { + // Use fallback. + encoding = "ISO-8859-1"; + } + + try + { + return forName(encoding); + } + catch(UnsupportedCharsetException e) + { + // Ignore. + } + catch(IllegalCharsetNameException e) + { + // Ignore. + } + catch(IllegalArgumentException e) + { + // Ignore. + } + + throw new IllegalStateException("Can't get default charset!"); + } + + public static boolean isSupported (String charsetName) + { + return charsetForName (charsetName) != null; + } + + /** + * Returns the Charset instance for the charset of the given name. + * + * @param charsetName + * @return + * @throws UnsupportedCharsetException if this VM does not support + * the charset of the given name. + * @throws IllegalCharsetNameException if the given charset name is + * legal. + * @throws IllegalArgumentException if <code>charsetName</code> is null. + */ + public static Charset forName (String charsetName) + { + // Throws IllegalArgumentException as the JDK does. + if(charsetName == null) + throw new IllegalArgumentException("Charset name must not be null."); + + Charset cs = charsetForName (charsetName); + if (cs == null) + throw new UnsupportedCharsetException (charsetName); + return cs; + } + + /** + * Retrieves a charset for the given charset name. + * + * @return A charset object for the charset with the specified name, or + * <code>null</code> if no such charset exists. + * + * @throws IllegalCharsetNameException if the name is illegal + */ + private static Charset charsetForName(String charsetName) + { + checkName (charsetName); + // Try the default provider first + // (so we don't need to load external providers unless really necessary) + // if it is an exotic charset try loading the external providers. + Charset cs = provider().charsetForName(charsetName); + if (cs == null) + { + CharsetProvider[] providers = providers2(); + for (int i = 0; i < providers.length; i++) + { + cs = providers[i].charsetForName(charsetName); + if (cs != null) + break; + } + } + return cs; + } + + public static SortedMap availableCharsets() + { + TreeMap charsets = new TreeMap(String.CASE_INSENSITIVE_ORDER); + for (Iterator i = provider().charsets(); i.hasNext(); ) + { + Charset cs = (Charset) i.next(); + charsets.put(cs.name(), cs); + } + + CharsetProvider[] providers = providers2(); + for (int j = 0; j < providers.length; j++) + { + for (Iterator i = providers[j].charsets(); i.hasNext(); ) + { + Charset cs = (Charset) i.next(); + charsets.put(cs.name(), cs); + } + } + + return Collections.unmodifiableSortedMap(charsets); + } + + private static CharsetProvider provider() + { + try + { + String s = System.getProperty("charset.provider"); + if (s != null) + { + CharsetProvider p = + (CharsetProvider) ((Class.forName(s)).newInstance()); + return p; + } + } + catch (Exception e) + { + // Ignore. + } + + return Provider.provider(); + } + + /** + * We need to support multiple providers, reading them from + * java.nio.charset.spi.CharsetProvider in the resource directory + * META-INF/services. This returns the "extra" charset providers. + */ + private static CharsetProvider[] providers2() + { + if (providers == null) + { + try + { + Iterator i = ServiceFactory.lookupProviders(CharsetProvider.class); + LinkedHashSet set = new LinkedHashSet(); + while (i.hasNext()) + set.add(i.next()); + + providers = new CharsetProvider[set.size()]; + set.toArray(providers); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } + return providers; + } + + public final String name () + { + return canonicalName; + } + + public final Set aliases () + { + if (aliases == null) + return Collections.EMPTY_SET; + + // should we cache the aliasSet instead? + int n = aliases.length; + HashSet aliasSet = new HashSet (n); + for (int i = 0; i < n; ++i) + aliasSet.add (aliases[i]); + return Collections.unmodifiableSet (aliasSet); + } + + public String displayName () + { + return canonicalName; + } + + public String displayName (Locale locale) + { + return canonicalName; + } + + public final boolean isRegistered () + { + return (!canonicalName.startsWith ("x-") + && !canonicalName.startsWith ("X-")); + } + + public abstract boolean contains (Charset cs); + + public abstract CharsetDecoder newDecoder (); + + public abstract CharsetEncoder newEncoder (); + + public boolean canEncode () + { + return true; + } + + // NB: This implementation serializes different threads calling + // Charset.encode(), a potential performance problem. It might + // be better to remove the cache, or use ThreadLocal to cache on + // a per-thread basis. + public final synchronized ByteBuffer encode (CharBuffer cb) + { + try + { + if (cachedEncoder == null) + { + cachedEncoder = newEncoder () + .onMalformedInput (CodingErrorAction.REPLACE) + .onUnmappableCharacter (CodingErrorAction.REPLACE); + } else + cachedEncoder.reset(); + return cachedEncoder.encode (cb); + } + catch (CharacterCodingException e) + { + throw new AssertionError (e); + } + } + + public final ByteBuffer encode (String str) + { + return encode (CharBuffer.wrap (str)); + } + + // NB: This implementation serializes different threads calling + // Charset.decode(), a potential performance problem. It might + // be better to remove the cache, or use ThreadLocal to cache on + // a per-thread basis. + public final synchronized CharBuffer decode (ByteBuffer bb) + { + try + { + if (cachedDecoder == null) + { + cachedDecoder = newDecoder () + .onMalformedInput (CodingErrorAction.REPLACE) + .onUnmappableCharacter (CodingErrorAction.REPLACE); + } else + cachedDecoder.reset(); + + return cachedDecoder.decode (bb); + } + catch (CharacterCodingException e) + { + throw new AssertionError (e); + } + } + + public final int compareTo (Object ob) + { + return canonicalName.compareToIgnoreCase (((Charset) ob).canonicalName); + } + + public final int hashCode () + { + return canonicalName.hashCode (); + } + + public final boolean equals (Object ob) + { + if (ob instanceof Charset) + return canonicalName.equalsIgnoreCase (((Charset) ob).canonicalName); + else + return false; + } + + public final String toString () + { + return canonicalName; + } +} diff --git a/gcc-4.2.1/libjava/java/nio/charset/spi/CharsetProvider.java b/gcc-4.2.1/libjava/java/nio/charset/spi/CharsetProvider.java new file mode 100644 index 000000000..e15153fe9 --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/charset/spi/CharsetProvider.java @@ -0,0 +1,96 @@ +/* CharsetProvider.java -- charset service provider interface + Copyright (C) 2002, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.nio.charset.spi; + +import java.nio.charset.Charset; +import java.util.Iterator; + + +/** + * This class allows an implementor to provide additional character sets. The + * subclass must have a nullary constructor, and be attached to charset + * implementation classes. These extensions are loaded via the context class + * loader. To provide the charset extension, all files named + * <code>META-INF/services/java.nio.charset.spi.CharsetProvider</code> are + * read from the classpath. Each one should be a UTF-8 encoded list of + * fully-qualified names of concrete subclasses of this class; whitespace is + * ignored, and '#' starts comments. Duplicates are ignored. The + * implementations must be accessible to the classloader that requests them. + * + * @author Eric Blake (ebb9@email.byu.edu) + * @see Charset + * @since 1.4 + * @status updated to 1.4 + */ +public abstract class CharsetProvider +{ + /** + * Initialize a new charset provider. This performs a security check on + * RuntimePermission("charsetProvider"). + * + * @throws SecurityException if building a new set is not allowed + */ + protected CharsetProvider() + { + // We only do the security check for custom providers, not for the + // built in ones. + SecurityManager s = System.getSecurityManager(); + if (s != null && + ! (this instanceof gnu.java.nio.charset.Provider)) + // GCJ LOCAL - We have the iconv provider in standard.omit + // || this instanceof gnu.java.nio.charset.iconv.IconvProvider)) + s.checkPermission(new RuntimePermission("charsetProvider")); + } + + /** + * Returns an iterator over the charsets defined by this provider. + * + * @return the iterator + * @see Charset#availableCharsets() + */ + public abstract Iterator charsets(); + + /** + * Returns the named charset, by canonical name or alias. + * + * @param name the name of the character + * + * @return the charset, or null if not supported + */ + public abstract Charset charsetForName(String name); +} // class CharsetProvider diff --git a/gcc-4.2.1/libjava/java/nio/natDirectByteBufferImpl.cc b/gcc-4.2.1/libjava/java/nio/natDirectByteBufferImpl.cc new file mode 100644 index 000000000..3119fdea3 --- /dev/null +++ b/gcc-4.2.1/libjava/java/nio/natDirectByteBufferImpl.cc @@ -0,0 +1,72 @@ +// natDirectByteBufferImpl.cc + +/* Copyright (C) 2003, 2004 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <stdlib.h> + +#include <gnu/gcj/RawData.h> +#include <java/nio/VMDirectByteBuffer.h> + +using gnu::gcj::RawData; + +RawData* +java::nio::VMDirectByteBuffer::allocate (jint capacity) +{ + return reinterpret_cast<gnu::gcj::RawData*> (::malloc (capacity)); +} + +void +java::nio::VMDirectByteBuffer::free (gnu::gcj::RawData* address) +{ + ::free (reinterpret_cast<void*> (address)); +} + +jbyte +java::nio::VMDirectByteBuffer::get (RawData* address, jint index) +{ + jbyte* pointer = reinterpret_cast<jbyte*> (address) + index; + return *pointer; +} + +void +java::nio::VMDirectByteBuffer::get (RawData* address, jint index, + jbyteArray dst, jint offset, jint length) +{ + jbyte* src = reinterpret_cast<jbyte*> (address) + index; + memcpy (elements (dst) + offset, src, length); +} + +void +java::nio::VMDirectByteBuffer::put (gnu::gcj::RawData* address, + jint index, jbyte value) +{ + jbyte* pointer = reinterpret_cast<jbyte*> (address) + index; + *pointer = value; +} + +RawData* +java::nio::VMDirectByteBuffer::adjustAddress (RawData* address, jint offset) +{ + jbyte* start = reinterpret_cast<jbyte*> (address) + offset; + return reinterpret_cast<RawData*>(start); +} + +void +java::nio::VMDirectByteBuffer::shiftDown (RawData* address, jint dst_offset, + jint src_offset, jint count) +{ + jbyte* dst = reinterpret_cast<jbyte*> (address) + dst_offset; + jbyte* src = reinterpret_cast<jbyte*> (address) + src_offset; + ::memmove(dst, src, count); +} diff --git a/gcc-4.2.1/libjava/java/security/Security.java b/gcc-4.2.1/libjava/java/security/Security.java new file mode 100644 index 000000000..630a55412 --- /dev/null +++ b/gcc-4.2.1/libjava/java/security/Security.java @@ -0,0 +1,714 @@ +/* Security.java --- Java base security class implementation + Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security; + +import gnu.classpath.SystemProperties; + +import gnu.classpath.Configuration; +// GCJ LOCAL - We don't have VMStackWalker yet. +// import gnu.classpath.VMStackWalker; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.Vector; + +/** + * This class centralizes all security properties and common security methods. + * One of its primary uses is to manage security providers. + * + * @author Mark Benvenuto (ivymccough@worldnet.att.net) + */ +public final class Security +{ + private static final String ALG_ALIAS = "Alg.Alias."; + + private static Vector providers = new Vector(); + private static Properties secprops = new Properties(); + + static + { + String base = SystemProperties.getProperty("gnu.classpath.home.url"); + String vendor = SystemProperties.getProperty("gnu.classpath.vm.shortname"); + + // Try VM specific security file + boolean loaded = loadProviders (base, vendor); + + // Append classpath standard provider if possible + if (!loadProviders (base, "classpath") + && !loaded + && providers.size() == 0) + { + if (Configuration.DEBUG) + { + /* No providers found and both security files failed to + * load properly. Give a warning in case of DEBUG is + * enabled. Could be done with java.util.logging later. + */ + System.err.println + ("WARNING: could not properly read security provider files:"); + System.err.println + (" " + base + "/security/" + vendor + + ".security"); + System.err.println + (" " + base + "/security/" + "classpath" + + ".security"); + System.err.println + (" Falling back to standard GNU security provider"); + } + // Note that this matches our classpath.security file. + providers.addElement (new gnu.java.security.provider.Gnu()); + providers.addElement(new gnu.javax.crypto.jce.GnuCrypto()); + providers.addElement(new gnu.javax.crypto.jce.GnuSasl()); + providers.addElement(new gnu.javax.net.ssl.provider.Jessie()); + providers.addElement(new gnu.javax.security.auth.callback.GnuCallbacks()); + } + } + // This class can't be instantiated. + private Security() + { + } + + /** + * Tries to load the vender specific security providers from the given base + * URL. Returns true if the resource could be read and completely parsed + * successfully, false otherwise. + */ + private static boolean loadProviders(String baseUrl, String vendor) + { + if (baseUrl == null || vendor == null) + return false; + + boolean result = true; + String secfilestr = baseUrl + "/security/" + vendor + ".security"; + try + { + InputStream fin = new URL(secfilestr).openStream(); + secprops.load(fin); + + int i = 1; + String name; + while ((name = secprops.getProperty("security.provider." + i)) != null) + { + Exception exception = null; + try + { + ClassLoader sys = ClassLoader.getSystemClassLoader(); + providers.addElement(Class.forName(name, true, sys).newInstance()); + } + catch (ClassNotFoundException x) + { + exception = x; + } + catch (InstantiationException x) + { + exception = x; + } + catch (IllegalAccessException x) + { + exception = x; + } + + if (exception != null) + { + System.err.println ("WARNING: Error loading security provider " + + name + ": " + exception); + result = false; + } + i++; + } + } + catch (IOException ignored) + { + result = false; + } + + return result; + } + + /** + * Returns the value associated to a designated property name for a given + * algorithm. + * + * @param algName + * the algorithm name. + * @param propName + * the name of the property to return. + * @return the value of the specified property or <code>null</code> if none + * found. + * @deprecated Use the provider-based and algorithm-independent + * {@link AlgorithmParameters} and {@link KeyFactory} engine + * classes instead. + */ + public static String getAlgorithmProperty(String algName, String propName) + { + if (algName == null || propName == null) + return null; + + String property = String.valueOf(propName) + "." + String.valueOf(algName); + Provider p; + for (Iterator i = providers.iterator(); i.hasNext(); ) + { + p = (Provider) i.next(); + for (Iterator j = p.keySet().iterator(); j.hasNext(); ) + { + String key = (String) j.next(); + if (key.equalsIgnoreCase(property)) + return p.getProperty(key); + } + } + return null; + } + + /** + * Inserts a new designated {@link Provider} at a designated (1-based) + * position in the current list of installed {@link Provider}s, + * + * @param provider + * the new {@link Provider} to add. + * @param position + * the position (starting from 1) of where to install + * <code>provider</code>. + * @return the actual position, in the list of installed Providers. Returns + * <code>-1</code> if <code>provider</code> was laready in the + * list. The actual position may be different than the desired + * <code>position</code>. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. + * @see #getProvider(String) + * @see #removeProvider(String) + * @see SecurityPermission + */ + public static int insertProviderAt(Provider provider, int position) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("insertProvider." + provider.getName()); + + position--; + int max = providers.size (); + for (int i = 0; i < max; i++) + { + if (((Provider) providers.elementAt(i)).getName().equals(provider.getName())) + return -1; + } + + if (position < 0) + position = 0; + if (position > max) + position = max; + + providers.insertElementAt(provider, position); + + return position + 1; + } + + /** + * Appends the designated new {@link Provider} to the current list of + * installed {@link Provider}s. + * + * @param provider + * the new {@link Provider} to append. + * @return the position (starting from 1) of <code>provider</code> in the + * current list of {@link Provider}s, or <code>-1</code> if + * <code>provider</code> was already there. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. + * @see #getProvider(String) + * @see #removeProvider(String) + * @see SecurityPermission + */ + public static int addProvider(Provider provider) + { + return insertProviderAt (provider, providers.size () + 1); + } + + /** + * Removes an already installed {@link Provider}, given its name, from the + * current list of installed {@link Provider}s. + * + * @param name + * the name of an already installed {@link Provider} to remove. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. + * @see #getProvider(String) + * @see #addProvider(Provider) + */ + public static void removeProvider(String name) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("removeProvider." + name); + + int max = providers.size (); + for (int i = 0; i < max; i++) + { + if (((Provider) providers.elementAt(i)).getName().equals(name)) + { + providers.remove(i); + break; + } + } + } + + /** + * Returns the current list of installed {@link Provider}s as an array + * ordered according to their installation preference order. + * + * @return an array of all the installed providers. + */ + public static Provider[] getProviders() + { + Provider[] array = new Provider[providers.size ()]; + providers.copyInto (array); + return array; + } + + /** + * Returns an already installed {@link Provider} given its name. + * + * @param name + * the name of an already installed {@link Provider}. + * @return the {@link Provider} known by <code>name</code>. Returns + * <code>null</code> if the current list of {@link Provider}s does + * not include one named <code>name</code>. + * @see #removeProvider(String) + * @see #addProvider(Provider) + */ + public static Provider getProvider(String name) + { + if (name == null) + return null; + else + { + name = name.trim(); + if (name.length() == 0) + return null; + } + Provider p; + int max = providers.size (); + for (int i = 0; i < max; i++) + { + p = (Provider) providers.elementAt(i); + if (p.getName().equals(name)) + return p; + } + return null; + } + + /** + * Returns the value associated with a Security propery. + * + * @param key + * the key of the property to fetch. + * @return the value of the Security property associated with + * <code>key</code>. Returns <code>null</code> if no such property + * was found. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. + * @see #setProperty(String, String) + * @see SecurityPermission + */ + public static String getProperty(String key) + { + // GCJ LOCAL - We don't have VMStackWalker yet. + // XXX To prevent infinite recursion when the SecurityManager calls us, + // don't do a security check if the caller is trusted (by virtue of having + // been loaded by the bootstrap class loader). + SecurityManager sm = System.getSecurityManager(); + // if (sm != null && VMStackWalker.getCallingClassLoader() != null) + if (sm != null) + sm.checkSecurityAccess("getProperty." + key); + + return secprops.getProperty(key); + } + + /** + * Sets or changes a designated Security property to a designated value. + * + * @param key + * the name of the property to set. + * @param datum + * the new value of the property. + * @throws SecurityException + * if a {@link SecurityManager} is installed and it disallows this + * operation. + * @see #getProperty(String) + * @see SecurityPermission + */ + public static void setProperty(String key, String datum) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkSecurityAccess("setProperty." + key); + + if (datum == null) + secprops.remove(key); + else + secprops.put(key, datum); + } + + /** + * For a given <i>service</i> (e.g. Signature, MessageDigest, etc...) this + * method returns the {@link Set} of all available algorithm names (instances + * of {@link String}, from all currently installed {@link Provider}s. + * + * @param serviceName + * the case-insensitive name of a service (e.g. Signature, + * MessageDigest, etc). + * @return a {@link Set} of {@link String}s containing the names of all + * algorithm names provided by all of the currently installed + * {@link Provider}s. + * @since 1.4 + */ + public static Set getAlgorithms(String serviceName) + { + HashSet result = new HashSet(); + if (serviceName == null || serviceName.length() == 0) + return result; + + serviceName = serviceName.trim(); + if (serviceName.length() == 0) + return result; + + serviceName = serviceName.toUpperCase()+"."; + Provider[] providers = getProviders(); + int ndx; + for (int i = 0; i < providers.length; i++) + for (Enumeration e = providers[i].propertyNames(); e.hasMoreElements(); ) + { + String service = ((String) e.nextElement()).trim(); + if (service.toUpperCase().startsWith(serviceName)) + { + service = service.substring(serviceName.length()).trim(); + ndx = service.indexOf(' '); // get rid of attributes + if (ndx != -1) + service = service.substring(0, ndx); + result.add(service); + } + } + return Collections.unmodifiableSet(result); + } + + /** + * Returns an array of currently installed {@link Provider}s, ordered + * according to their installation preference order, which satisfy a given + * <i>selection</i> criterion. + * + * <p>This implementation recognizes a <i>selection</i> criterion written in + * one of two following forms:</p> + * + * <ul> + * <li><crypto_service>.<algorithm_or_type>: Where + * <i>crypto_service</i> is a case-insensitive string, similar to what has + * been described in the {@link #getAlgorithms(String)} method, and + * <i>algorithm_or_type</i> is a known case-insensitive name of an + * Algorithm, or one of its aliases. + * + * <p>For example, "CertificateFactory.X.509" would return all the installed + * {@link Provider}s which provide a <i>CertificateFactory</i> + * implementation of <i>X.509</i>.</p></li> + * + * <li><crypto_service>.<algorithm_or_type> <attribute_name>:<value>: + * Where <i>crypto_service</i> is a case-insensitive string, similar to what + * has been described in the {@link #getAlgorithms(String)} method, + * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm + * or one of its aliases, <i>attribute_name</i> is a case-insensitive + * property name with no whitespace characters, and no dots, in-between, and + * <i>value</i> is a {@link String} with no whitespace characters in-between. + * + * <p>For example, "Signature.Sha1WithDSS KeySize:1024" would return all the + * installed {@link Provider}s which declared their ability to provide + * <i>Signature</i> services, using the <i>Sha1WithDSS</i> algorithm with + * key sizes of <i>1024</i>.</p></li> + * </ul> + * + * @param filter + * the <i>selection</i> criterion for selecting among the installed + * {@link Provider}s. + * @return all the installed {@link Provider}s which satisfy the <i>selection</i> + * criterion. Returns <code>null</code> if no installed + * {@link Provider}s were found which satisfy the <i>selection</i> + * criterion. Returns ALL installed {@link Provider}s if + * <code>filter</code> is <code>null</code> or is an empty string. + * @throws InvalidParameterException + * if an exception occurs while parsing the <code>filter</code>. + * @see #getProviders(Map) + */ + public static Provider[] getProviders(String filter) + { + if (providers == null || providers.isEmpty()) + return null; + + if (filter == null || filter.length() == 0) + return getProviders(); + + HashMap map = new HashMap(1); + int i = filter.indexOf(':'); + if (i == -1) // <service>.<algorithm> + map.put(filter, ""); + else // <service>.<algorithm> <attribute>:<value> + map.put(filter.substring(0, i), filter.substring(i+1)); + + return getProviders(map); + } + + /** + * Returns an array of currently installed {@link Provider}s which satisfy a + * set of <i>selection</i> criteria. + * + * <p>The <i>selection</i> criteria are defined in a {@link Map} where each + * element specifies a <i>selection</i> querry. The <i>Keys</i> in this + * {@link Map} must be in one of the two following forms:</p> + * + * <ul> + * <li><crypto_service>.<algorithm_or_type>: Where + * <i>crypto_service</i> is a case-insensitive string, similar to what has + * been described in the {@link #getAlgorithms(String)} method, and + * <i>algorithm_or_type</i> is a case-insensitive known name of an + * Algorithm, or one of its aliases. The <i>value</i> of the entry in the + * {@link Map} for such a <i>Key</i> MUST be the empty string. + * {@link Provider}s which provide an implementation for the designated + * <i>service algorithm</i> are included in the result.</li> + * + * <li><crypto_service>.<algorithm_or_type> <attribute_name>: + * Where <i>crypto_service</i> is a case-insensitive string, similar to what + * has been described in the {@link #getAlgorithms(String)} method, + * <i>algorithm_or_type</i> is a case-insensitive known name of an Algorithm + * or one of its aliases, and <i>attribute_name</i> is a case-insensitive + * property name with no whitespace characters, and no dots, in-between. The + * <i>value</i> of the entry in this {@link Map} for such a <i>Key</i> MUST + * NOT be <code>null</code> or an empty string. {@link Provider}s which + * declare the designated <i>attribute_name</i> and <i>value</i> for the + * designated <i>service algorithm</i> are included in the result.</li> + * </ul> + * + * @param filter + * a {@link Map} of <i>selection querries</i>. + * @return all currently installed {@link Provider}s which satisfy ALL the + * <i>selection</i> criteria defined in <code>filter</code>. + * Returns ALL installed {@link Provider}s if <code>filter</code> + * is <code>null</code> or empty. + * @throws InvalidParameterException + * if an exception is encountered while parsing the syntax of the + * {@link Map}'s <i>keys</i>. + * @see #getProviders(String) + */ + public static Provider[] getProviders(Map filter) + { + if (providers == null || providers.isEmpty()) + return null; + + if (filter == null) + return getProviders(); + + Set querries = filter.keySet(); + if (querries == null || querries.isEmpty()) + return getProviders(); + + LinkedHashSet result = new LinkedHashSet(providers); // assume all + int dot, ws; + String querry, service, algorithm, attribute, value; + LinkedHashSet serviceProviders = new LinkedHashSet(); // preserve insertion order + for (Iterator i = querries.iterator(); i.hasNext(); ) + { + querry = (String) i.next(); + if (querry == null) // all providers + continue; + + querry = querry.trim(); + if (querry.length() == 0) // all providers + continue; + + dot = querry.indexOf('.'); + if (dot == -1) // syntax error + throw new InvalidParameterException( + "missing dot in '" + String.valueOf(querry)+"'"); + + value = (String) filter.get(querry); + // deconstruct querry into [service, algorithm, attribute] + if (value == null || value.trim().length() == 0) // <service>.<algorithm> + { + value = null; + attribute = null; + service = querry.substring(0, dot).trim(); + algorithm = querry.substring(dot+1).trim(); + } + else // <service>.<algorithm> <attribute> + { + ws = querry.indexOf(' '); + if (ws == -1) + throw new InvalidParameterException( + "value (" + String.valueOf(value) + + ") is not empty, but querry (" + String.valueOf(querry) + + ") is missing at least one space character"); + value = value.trim(); + attribute = querry.substring(ws+1).trim(); + // was the dot in the attribute? + if (attribute.indexOf('.') != -1) + throw new InvalidParameterException( + "attribute_name (" + String.valueOf(attribute) + + ") in querry (" + String.valueOf(querry) + ") contains a dot"); + + querry = querry.substring(0, ws).trim(); + service = querry.substring(0, dot).trim(); + algorithm = querry.substring(dot+1).trim(); + } + + // service and algorithm must not be empty + if (service.length() == 0) + throw new InvalidParameterException( + "<crypto_service> in querry (" + String.valueOf(querry) + + ") is empty"); + + if (algorithm.length() == 0) + throw new InvalidParameterException( + "<algorithm_or_type> in querry (" + String.valueOf(querry) + + ") is empty"); + + selectProviders(service, algorithm, attribute, value, result, serviceProviders); + result.retainAll(serviceProviders); // eval next retaining found providers + if (result.isEmpty()) // no point continuing + break; + } + + if (result.isEmpty()) + return null; + + return (Provider[]) result.toArray(new Provider[result.size()]); + } + + private static void selectProviders(String svc, String algo, String attr, + String val, LinkedHashSet providerSet, + LinkedHashSet result) + { + result.clear(); // ensure we start with an empty result set + for (Iterator i = providerSet.iterator(); i.hasNext(); ) + { + Provider p = (Provider) i.next(); + if (provides(p, svc, algo, attr, val)) + result.add(p); + } + } + + private static boolean provides(Provider p, String svc, String algo, + String attr, String val) + { + Iterator it; + String serviceDotAlgorithm = null; + String key = null; + String realVal; + boolean found = false; + // if <svc>.<algo> <attr> is in the set then so is <svc>.<algo> + // but it may be stored under an alias <algo>. resolve + outer: for (int r = 0; r < 3; r++) // guard against circularity + { + serviceDotAlgorithm = (svc+"."+String.valueOf(algo)).trim(); + for (it = p.keySet().iterator(); it.hasNext(); ) + { + key = (String) it.next(); + if (key.equalsIgnoreCase(serviceDotAlgorithm)) // eureka + { + found = true; + break outer; + } + // it may be there but as an alias + if (key.equalsIgnoreCase(ALG_ALIAS + serviceDotAlgorithm)) + { + algo = p.getProperty(key); + continue outer; + } + // else continue inner + } + } + + if (!found) + return false; + + // found a candidate for the querry. do we have an attr to match? + if (val == null) // <service>.<algorithm> querry + return true; + + // <service>.<algorithm> <attribute>; find the key entry that match + String realAttr; + int limit = serviceDotAlgorithm.length() + 1; + for (it = p.keySet().iterator(); it.hasNext(); ) + { + key = (String) it.next(); + if (key.length() <= limit) + continue; + + if (key.substring(0, limit).equalsIgnoreCase(serviceDotAlgorithm+" ")) + { + realAttr = key.substring(limit).trim(); + if (! realAttr.equalsIgnoreCase(attr)) + continue; + + // eveything matches so far. do the value + realVal = p.getProperty(key); + if (realVal == null) + return false; + + realVal = realVal.trim(); + // is it a string value? + if (val.equalsIgnoreCase(realVal)) + return true; + + // assume value is a number. cehck for greater-than-or-equal + return (new Integer(val).intValue() >= new Integer(realVal).intValue()); + } + } + + return false; + } +} diff --git a/gcc-4.2.1/libjava/java/security/VMAccessControlState.java b/gcc-4.2.1/libjava/java/security/VMAccessControlState.java new file mode 100644 index 000000000..360f08a5b --- /dev/null +++ b/gcc-4.2.1/libjava/java/security/VMAccessControlState.java @@ -0,0 +1,103 @@ +/* VMAccessControlState.java -- per-thread state for the access controller. + Copyright (C) 2006 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security; + +import java.util.LinkedList; + +class VMAccessControlState +{ + /** + * A list of {@link AccessControlContext} objects (which can be + * null) for each call to {@link AccessController#doPrivileged()} in + * the thread's call stack. + */ + private LinkedList contexts = new LinkedList(); + + /** + * A flag indicating that we are within a call to {@link + * VMAccessController#getContext()}. + */ + private boolean inGetContext = false; + + /** + * Not directly instantiable: use getThreadState() instead. + */ + private VMAccessControlState() {} + + /** + * Return an object representing the access control state of this + * thread. + * + * @return The access control state of this thread, or + * <code>null</code> if the VM is not initialized to the point of + * being able to return this. + */ + static native VMAccessControlState getThreadState(); + + /** + * Indicate whether this thread is within a call to {@link + * VMAccessController#getContext()}. + * + * @return <code>true</code> if this thread is within a call to + * {@link VMAccessController#getContext()}. + */ + boolean isInGetContext() + { + return inGetContext; + } + + /** + * Specify whether this thread is within a call to {@link + * VMAccessController#getContext()}. + */ + void setInGetContext(boolean inGetContext) + { + this.inGetContext = inGetContext; + } + + /** + * Return a list of {@link AccessControlContext} objects (which can + * be null) for each call to {@link AccessController#doPrivileged()} + * in the thread's call stack. + * + * @return a list of {@link AccessControlContext} objects. + */ + LinkedList getContexts() + { + return contexts; + } +} diff --git a/gcc-4.2.1/libjava/java/security/VMAccessController.java b/gcc-4.2.1/libjava/java/security/VMAccessController.java new file mode 100644 index 000000000..8436c9ccb --- /dev/null +++ b/gcc-4.2.1/libjava/java/security/VMAccessController.java @@ -0,0 +1,255 @@ +/* VMAccessController.java -- VM-specific access controller methods. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security; + +import java.util.HashSet; +import java.util.LinkedList; + +final class VMAccessController +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * And we return this all-permissive context to ensure that privileged + * methods called from getContext succeed. + */ + private static final AccessControlContext DEFAULT_CONTEXT; + static + { + CodeSource source = new CodeSource(null, null); + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + ProtectionDomain[] domain = new ProtectionDomain[] { + new ProtectionDomain(source, permissions) + }; + DEFAULT_CONTEXT = new AccessControlContext(domain); + } + + private static final boolean DEBUG = gnu.classpath.Configuration.DEBUG; + private static void debug(String msg) + { + System.err.print(">>> VMAccessController: "); + System.err.println(msg); + } + + // Constructors. + // ------------------------------------------------------------------------- + + private VMAccessController() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Relate a class (which should be an instance of {@link PrivilegedAction} + * with an access control context. This method is used by {@link + * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)} + * to set up the context that will be returned by {@link #getContext()}. + * This method relates the class to the current thread, so contexts + * pushed from one thread will not be available to another. + * + * @param acc The access control context. + */ + static void pushContext (AccessControlContext acc) + { + // Can't really do anything while the VM is initializing. + VMAccessControlState state = VMAccessControlState.getThreadState(); + if (state == null) + return; + + if (DEBUG) + debug("pushing " + acc); + + LinkedList stack = state.getContexts(); + stack.addFirst(acc); + } + + /** + * Removes the relation of a class to an {@link AccessControlContext}. + * This method is used by {@link AccessController} when exiting from a + * call to {@link + * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}. + */ + static void popContext() + { + // Can't really do anything while the VM is initializing. + VMAccessControlState state = VMAccessControlState.getThreadState(); + if (state == null) + return; + + if (DEBUG) + debug("popping context"); + + // Stack should never be null, nor should it be empty, if this method + // and its counterpart has been called properly. + LinkedList stack = state.getContexts(); + if (!stack.isEmpty()) + { + stack.removeFirst(); + } + else if (DEBUG) + { + debug("no stack during pop?????"); + } + } + + /** + * Examine the method stack of the currently running thread, and create + * an {@link AccessControlContext} filled in with the appropriate {@link + * ProtectionDomain} objects given this stack. + * + * @return The context. + */ + static AccessControlContext getContext() + { + // If the VM is initializing return the all-permissive context + // so that any security checks succeed. + VMAccessControlState state = VMAccessControlState.getThreadState(); + if (state == null) + return DEFAULT_CONTEXT; + + // If we are already in getContext, but called a method that needs + // a permission check, return the all-permissive context so methods + // called from here succeed. + // + // XXX is this necessary? We should verify if there are any calls in + // the stack below this method that require permission checks. + if (state.isInGetContext()) + { + if (DEBUG) + debug("already in getContext"); + return DEFAULT_CONTEXT; + } + + state.setInGetContext(true); + + Object[] stack = getStack(); + Class[] classes = (Class[]) stack[0]; + boolean privileged = ((Boolean) stack[1]).booleanValue(); + + if (DEBUG) + debug("got trace of length " + classes.length); + + HashSet domains = new HashSet(); + HashSet seenDomains = new HashSet(); + AccessControlContext context = null; + + // We walk down the stack, adding each ProtectionDomain for each + // class in the call stack. If we reach a call to doPrivileged, + // we don't add any more stack frames. We skip the first three stack + // frames, since they comprise the calls to getStack, getContext, + // and AccessController.getContext. + for (int i = 3; i < classes.length; i++) + { + Class clazz = classes[i]; + + if (DEBUG) + { + debug("checking " + clazz); + // subject to getClassLoader RuntimePermission + debug("loader = " + clazz.getClassLoader()); + } + + if (privileged && i == classes.length - 2) + { + // If there was a call to doPrivileged with a supplied context, + // return that context. If using JAAS doAs*, it should be + // a context with a SubjectDomainCombiner + LinkedList l = state.getContexts(); + if (!l.isEmpty()) + context = (AccessControlContext) l.getFirst(); + } + + // subject to getProtectionDomain RuntimePermission + ProtectionDomain domain = clazz.getProtectionDomain(); + + if (domain == null) + continue; + if (seenDomains.contains(domain)) + continue; + seenDomains.add(domain); + + // Create a static snapshot of this domain, which may change over time + // if the current policy changes. + domains.add(new ProtectionDomain(domain.getCodeSource(), + domain.getPermissions())); + } + + if (DEBUG) + debug("created domains: " + domains); + + ProtectionDomain[] result = (ProtectionDomain[]) + domains.toArray(new ProtectionDomain[domains.size()]); + + if (context != null) + { + DomainCombiner dc = context.getDomainCombiner (); + // If the supplied context had no explicit DomainCombiner, use + // our private version, which computes the intersection of the + // context's domains with the derived set. + if (dc == null) + context = new AccessControlContext + (IntersectingDomainCombiner.SINGLETON.combine + (result, context.getProtectionDomains ())); + // Use the supplied DomainCombiner. This should be secure, + // because only trusted code may create an + // AccessControlContext with a custom DomainCombiner. + else + context = new AccessControlContext (result, context, dc); + } + // No context was supplied. Return the derived one. + else + context = new AccessControlContext (result); + + state.setInGetContext(false); + return context; + } + + /** + * Returns a snapshot of the current call stack as a two-element + * array. The first element is an array of classes in the call + * stack, and the second element is a boolean value indicating + * whether the trace stopped early because a call to doPrivileged + * was encountered. If this boolean value is true then the call to + * doPrivileged will be the second-last frame in the returned trace. + * + * @return A snapshot of the current call stack. + */ + private static native Object[] getStack(); +} diff --git a/gcc-4.2.1/libjava/java/security/VMSecureRandom.java b/gcc-4.2.1/libjava/java/security/VMSecureRandom.java new file mode 100644 index 000000000..dc67d8719 --- /dev/null +++ b/gcc-4.2.1/libjava/java/security/VMSecureRandom.java @@ -0,0 +1,134 @@ +/* VMSecureRandom.java -- random seed generator. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security; + +import gnu.classpath.SystemProperties; +import gnu.java.security.action.GetSecurityPropertyAction; + +import java.net.URL; + +/** + * VM-specific methods for generating real (or almost real) random + * seeds. VM implementors should write a version of this class that + * reads random bytes from some system source. + * + * <p>The default implementation of this class runs eight threads that + * increment counters in a tight loop, and XORs each counter to + * produce one byte of seed data. This is not very efficient, and is + * not guaranteed to be random (the thread scheduler is probably + * deterministic, after all). If possible, VM implementors should + * reimplement this class so it obtains a random seed from a system + * facility, such as a system entropy gathering device or hardware + * random number generator. + */ +final class VMSecureRandom +{ + + /** + * Generate a random seed. Implementations are free to generate + * fewer random bytes than are requested, and leave the remaining + * bytes of the destination buffer as zeros. Implementations SHOULD, + * however, make a best-effort attempt to satisfy the request. + * + * @param buffer The destination buffer. + * @param offset The offset in the buffer to start putting bytes. + * @param length The number of random bytes to generate. + */ + static int generateSeed(byte[] buffer, int offset, int length) + { + if (length < 0) + throw new IllegalArgumentException("length must be nonnegative"); + if (offset < 0 || offset + length > buffer.length) + throw new IndexOutOfBoundsException(); + + Spinner[] spinners = new Spinner[8]; + int n = 0x1; + for (int i = 0; i < spinners.length; i++) + { + spinners[i] = new Spinner((byte) n); + Thread t = new Thread(spinners[i]); + t.start(); + n <<= 1; + } + + // Wait until at least one spinner has started. + while (!(spinners[0].running || spinners[1].running || spinners[2].running + || spinners[3].running || spinners[4].running || spinners[5].running + || spinners[6].running || spinners[7].running)) + { + Thread.yield(); + } + + for (int i = offset; i < length; i++) + { + buffer[i] = (byte) (spinners[0].value ^ spinners[1].value ^ spinners[2].value + ^ spinners[3].value ^ spinners[4].value ^ spinners[5].value + ^ spinners[6].value ^ spinners[7].value); + Thread.yield(); + } + + for (int i = 0; i < spinners.length; i++) + spinners[i].stop(); + + return length; + } + + static class Spinner implements Runnable + { + volatile byte value; + volatile boolean running; + + Spinner(final byte initial) + { + value = initial; + } + + public void run() + { + running = true; + while (running) + value++; + } + + private void stop() + { + running = false; + } + } +}
\ No newline at end of file diff --git a/gcc-4.2.1/libjava/java/security/natVMAccessControlState.cc b/gcc-4.2.1/libjava/java/security/natVMAccessControlState.cc new file mode 100644 index 000000000..a4c14cdd4 --- /dev/null +++ b/gcc-4.2.1/libjava/java/security/natVMAccessControlState.cc @@ -0,0 +1,32 @@ +// natVMAccessControlState.cc -- Native part of the VMAccessControlState class. + +/* Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/lang/Thread.h> +#include <java/security/VMAccessControlState.h> + +java::security::VMAccessControlState * +java::security::VMAccessControlState::getThreadState () +{ + java::lang::Thread *thread = java::lang::Thread::currentThread (); + if (thread == NULL) + return NULL; + + VMAccessControlState *state = + reinterpret_cast<VMAccessControlState *> (thread->accessControlState); + if (state == NULL) + thread->accessControlState = state = new VMAccessControlState (); + + return state; +} diff --git a/gcc-4.2.1/libjava/java/security/natVMAccessController.cc b/gcc-4.2.1/libjava/java/security/natVMAccessController.cc new file mode 100644 index 000000000..9a0ae489e --- /dev/null +++ b/gcc-4.2.1/libjava/java/security/natVMAccessController.cc @@ -0,0 +1,23 @@ +// natVMAccessController.cc -- Native part of the VMAccessController class. + +/* Copyright (C) 2006 Free Software Foundation, Inc. + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/security/VMAccessController.h> + +jobjectArray +java::security::VMAccessController::getStack () +{ + return _Jv_StackTrace::GetAccessControlStack (); +} diff --git a/gcc-4.2.1/libjava/java/text/Collator.java b/gcc-4.2.1/libjava/java/text/Collator.java new file mode 100644 index 000000000..c1ba87e93 --- /dev/null +++ b/gcc-4.2.1/libjava/java/text/Collator.java @@ -0,0 +1,395 @@ +/* Collator.java -- Perform locale dependent String comparisons. + Copyright (C) 1998, 1999, 2000, 2001, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +import java.util.Comparator; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class is the abstract superclass of classes which perform + * locale dependent <code>String</code> comparisons. A caller requests + * an instance of <code>Collator</code> for a particular locale using + * the <code>getInstance()</code> static method in this class. That method + * will return a locale specific subclass of <code>Collator</code> which + * can be used to perform <code>String</code> comparisons for that locale. + * If a subclass of <code>Collator</code> cannot be located for a particular + * locale, a default instance for the current locale will be returned. + * + * In addition to setting the correct locale, there are two additional + * settings that can be adjusted to affect <code>String</code> comparisons: + * strength and decomposition. The strength value determines the level + * of signficance of character differences required for them to sort + * differently. (For example, whether or not capital letters are considered + * different from lower case letters). The decomposition value affects how + * variants of the same character are treated for sorting purposes. (For + * example, whether or not an accent is signficant or not). These settings + * are described in detail in the documentation for the methods and values + * that are related to them. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date March 18, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Mostly complete, but parts stubbed out. Look for FIXME. + */ +public abstract class Collator implements Comparator, Cloneable +{ + /** + * This constant is a strength value which indicates that only primary + * differences between characters will be considered signficant. As an + * example, two completely different English letters such as 'a' and 'b' + * are considered to have a primary difference. + */ + public static final int PRIMARY = 0; + + /** + * This constant is a strength value which indicates that only secondary + * or primary differences between characters will be considered + * significant. An example of a secondary difference between characters + * are instances of the same letter with different accented forms. + */ + public static final int SECONDARY = 1; + + /** + * This constant is a strength value which indicates that tertiary, + * secondary, and primary differences will be considered during sorting. + * An example of a tertiary difference is capitalization of a given letter. + * This is the default value for the strength setting. + */ + public static final int TERTIARY = 2; + + /** + * This constant is a strength value which indicates that any difference + * at all between character values are considered significant. + */ + public static final int IDENTICAL = 3; + + /** + * This constant indicates that accented characters won't be decomposed + * when performing comparisons. This will yield the fastest results, but + * will only work correctly in call cases for languages which do not + * use accents such as English. + */ + public static final int NO_DECOMPOSITION = 0; + + /** + * This constant indicates that only characters which are canonical variants + * in Unicode 2.0 will be decomposed prior to performing comparisons. This + * will cause accented languages to be sorted correctly. This is the + * default decomposition value. + */ + public static final int CANONICAL_DECOMPOSITION = 1; + + /** + * This constant indicates that both canonical variants and compatibility + * variants in Unicode 2.0 will be decomposed prior to performing + * comparisons. This is the slowest mode, but is required to get the + * correct sorting for certain languages with certain special formats. + */ + public static final int FULL_DECOMPOSITION = 2; + + /** + * This method initializes a new instance of <code>Collator</code> to have + * the default strength (TERTIARY) and decomposition + * (CANONICAL_DECOMPOSITION) settings. This constructor is protected and + * is for use by subclasses only. Non-subclass callers should use the + * static <code>getInstance()</code> methods of this class to instantiate + * <code>Collation</code> objects for the desired locale. + */ + protected Collator () + { + strength = TERTIARY; + decmp = CANONICAL_DECOMPOSITION; + } + + /** + * This method compares the two <code>String</code>'s and returns an + * integer indicating whether or not the first argument is less than, + * equal to, or greater than the second argument. The comparison is + * performed according to the rules of the locale for this + * <code>Collator</code> and the strength and decomposition rules in + * effect. + * + * @param source The first object to compare + * @param target The second object to compare + * + * @return A negative integer if str1 < str2, 0 if str1 == str2, or + * a positive integer if str1 > str2. + */ + public abstract int compare (String source, String target); + + /** + * This method compares the two <code>Object</code>'s and returns an + * integer indicating whether or not the first argument is less than, + * equal to, or greater than the second argument. These two objects + * must be <code>String</code>'s or an exception will be thrown. + * + * @param o1 The first object to compare + * @param o2 The second object to compare + * + * @return A negative integer if obj1 < obj2, 0 if obj1 == obj2, or + * a positive integer if obj1 > obj2. + * + * @exception ClassCastException If the arguments are not instances + * of <code>String</code>. + */ + public int compare (Object o1, Object o2) + { + return compare ((String) o1, (String) o2); + } + + /** + * This method tests the specified object for equality against this + * object. This will be true if and only if the following conditions are + * met: + * <ul> + * <li>The specified object is not <code>null</code>.</li> + * <li>The specified object is an instance of <code>Collator</code>.</li> + * <li>The specified object has the same strength and decomposition + * settings as this object.</li> + * </ul> + * + * @param obj The <code>Object</code> to test for equality against + * this object. + * + * @return <code>true</code> if the specified object is equal to + * this one, <code>false</code> otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof Collator)) + return false; + Collator c = (Collator) obj; + return decmp == c.decmp && strength == c.strength; + } + + /** + * This method tests whether the specified <code>String</code>'s are equal + * according to the collation rules for the locale of this object and + * the current strength and decomposition settings. + * + * @param source The first <code>String</code> to compare + * @param target The second <code>String</code> to compare + * + * @return <code>true</code> if the two strings are equal, + * <code>false</code> otherwise. + */ + public boolean equals (String source, String target) + { + return compare (source, target) == 0; + } + + /** + * This method returns a copy of this <code>Collator</code> object. + * + * @return A duplicate of this object. + */ + public Object clone () + { + try + { + return super.clone (); + } + catch (CloneNotSupportedException _) + { + return null; + } + } + + /** + * This method returns an array of <code>Locale</code> objects which is + * the list of locales for which <code>Collator</code> objects exist. + * + * @return The list of locales for which <code>Collator</code>'s exist. + */ + public static synchronized Locale[] getAvailableLocales () + { + // FIXME + Locale[] l = new Locale[1]; + l[0] = Locale.US; + return l; + } + + /** + * This method transforms the specified <code>String</code> into a + * <code>CollationKey</code> for faster comparisons. This is useful when + * comparisons against a string might be performed multiple times, such + * as during a sort operation. + * + * @param source The <code>String</code> to convert. + * + * @return A <code>CollationKey</code> for the specified <code>String</code>. + */ + public abstract CollationKey getCollationKey (String source); + + /** + * This method returns the current decomposition setting for this + * object. This * will be one of NO_DECOMPOSITION, + * CANONICAL_DECOMPOSITION, or * FULL_DECOMPOSITION. See the + * documentation for those constants for an * explanation of this + * setting. + * + * @return The current decomposition setting. + */ + public synchronized int getDecomposition () + { + return decmp; + } + + /** + * This method returns an instance of <code>Collator</code> for the + * default locale. + * + * @return A <code>Collator</code> for the default locale. + */ + public static Collator getInstance () + { + return getInstance (Locale.getDefault()); + } + + /** + * This method returns an instance of <code>Collator</code> for the + * specified locale. If no <code>Collator</code> exists for the desired + * locale, a <code>Collator</code> for the default locale will be returned. + * + * @param loc The desired localed to load a <code>Collator</code> for. + * + * @return A <code>Collator</code> for the requested locale + */ + public static Collator getInstance (Locale loc) + { + ResourceBundle res; + String pattern; + try + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + pattern = res.getString("collation_rules"); + } + catch (MissingResourceException x) + { + pattern = "<0<1<2<3<4<5<6<7<8<9<A,a<b,B<c,C<d,D<e,E<f,F<g,G<h,H<i,I<j,J<k,K" + + "<l,L<m,M<n,N<o,O<p,P<q,Q<r,R<s,S<t,T<u,U<v,V<w,W<x,X<y,Y<z,Z"; + } + try + { + return new RuleBasedCollator (pattern); + } + catch (ParseException x) + { + throw (InternalError)new InternalError().initCause(x); + } + } + + /** + * This method returns the current strength setting for this object. This + * will be one of PRIMARY, SECONDARY, TERTIARY, or IDENTICAL. See the + * documentation for those constants for an explanation of this setting. + * + * @return The current strength setting. + */ + public synchronized int getStrength () + { + return strength; + } + + /** + * This method returns a hash code value for this object. + * + * @return A hash value for this object. + */ + public abstract int hashCode (); + + /** + * This method sets the decomposition setting for this object to the + * specified value. This must be one of NO_DECOMPOSITION, + * CANONICAL_DECOMPOSITION, or FULL_DECOMPOSITION. Otherwise an + * exception will be thrown. See the documentation for those + * contants for an explanation of this setting. + * + * @param mode The new decomposition setting. + * + * @exception IllegalArgumentException If the requested + * decomposition setting is not valid. + */ + public synchronized void setDecomposition (int mode) + { + if (mode != NO_DECOMPOSITION + && mode != CANONICAL_DECOMPOSITION + && mode != FULL_DECOMPOSITION) + throw new IllegalArgumentException (); + decmp = mode; + } + + /** + * This method sets the strength setting for this object to the specified + * value. This must be one of PRIMARY, SECONDARY, TERTIARY, or IDENTICAL. + * Otherwise an exception is thrown. See the documentation for these + * constants for an explanation of this setting. + * + * @param strength The new strength setting. + * + * @exception IllegalArgumentException If the requested strength + * setting value is not valid. + */ + public synchronized void setStrength (int strength) + { + if (strength != PRIMARY && strength != SECONDARY + && strength != TERTIARY && strength != IDENTICAL) + throw new IllegalArgumentException (); + this.strength = strength; + } + + // Decompose a single character and append results to the buffer. + native final void decomposeCharacter (char c, StringBuffer buf); + + /** + * This is the current collation decomposition setting. + */ + int decmp; + + /** + * This is the current collation strength setting. + */ + int strength; +} diff --git a/gcc-4.2.1/libjava/java/text/DateFormatSymbols.java b/gcc-4.2.1/libjava/java/text/DateFormatSymbols.java new file mode 100644 index 000000000..27a806df1 --- /dev/null +++ b/gcc-4.2.1/libjava/java/text/DateFormatSymbols.java @@ -0,0 +1,502 @@ +/* DateFormatSymbols.java -- Format over a range of numbers + Copyright (C) 1998, 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class acts as container for locale specific date/time formatting + * information such as the days of the week and the months of the year. + * @author Per Bothner (bothner@cygnus.com) + * @date October 24, 1998. + */ +/* Written using "Java Class Libraries", 2nd edition, ISBN 0-201-31002-3. + * Status: Believed complete and correct. + */ +public class DateFormatSymbols implements java.io.Serializable, Cloneable +{ + String[] ampms; + String[] eras; + private String localPatternChars; + String[] months; + String[] shortMonths; + String[] shortWeekdays; + String[] weekdays; + private String[][] zoneStrings; + + private static final long serialVersionUID = -5987973545549424702L; + + // The order of these prefixes must be the same as in DateFormat + private static final String[] formatPrefixes = + { + "full", "long", "medium", "short" + }; + + // These are each arrays with a value for SHORT, MEDIUM, LONG, FULL, + // and DEFAULT (constants defined in java.text.DateFormat). While + // not part of the official spec, we need a way to get at locale-specific + // default formatting patterns. They are declared package scope so + // as to be easily accessible where needed (DateFormat, SimpleDateFormat). + transient String[] dateFormats; + transient String[] timeFormats; + + private String[] formatsForKey(ResourceBundle res, String key) + { + String[] values = new String [formatPrefixes.length]; + for (int i = 0; i < formatPrefixes.length; i++) + { + values[i] = res.getString(formatPrefixes[i]+key); + } + return values; + } + + /** + * This method initializes a new instance of <code>DateFormatSymbols</code> + * by loading the date format information for the specified locale. + * + * @param locale The locale for which date formatting symbols should + * be loaded. + */ + public DateFormatSymbols (Locale locale) throws MissingResourceException + { + ResourceBundle res + = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", locale, + ClassLoader.getSystemClassLoader()); + + ampms = res.getStringArray ("ampms"); + eras = res.getStringArray ("eras"); + localPatternChars = res.getString ("localPatternChars"); + months = res.getStringArray ("months"); + shortMonths = res.getStringArray ("shortMonths"); + shortWeekdays = res.getStringArray ("shortWeekdays"); + weekdays = res.getStringArray ("weekdays"); + zoneStrings = (String[][]) res.getObject ("zoneStrings"); + + dateFormats = formatsForKey(res, "DateFormat"); + timeFormats = formatsForKey(res, "TimeFormat"); + } + + /** + * This method loads the format symbol information for the default + * locale. + */ + public DateFormatSymbols () throws MissingResourceException + { + this (Locale.getDefault()); + } + + /** + * This method returns the list of strings used for displaying AM or PM. + * This is a two element <code>String</code> array indexed by + * <code>Calendar.AM</code> and <code>Calendar.PM</code> + * + * @return The list of AM/PM display strings. + */ + public String[] getAmPmStrings() + { + return ampms; + } + + /** + * This method returns the list of strings used for displaying eras + * (e.g., "BC" and "AD"). This is a two element <code>String</code> + * array indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>. + * + * @return The list of era disply strings. + */ + public String[] getEras() + { + return eras; + } + + /** + * This method returns the pattern character information for this + * object. This is an 18 character string that contains the characters + * that are used in creating the date formatting strings in + * <code>SimpleDateFormat</code>. The following are the character + * positions in the string and which format character they correspond + * to (the character in parentheses is the default value in the US English + * locale): + * <p> + * <ul> + * <li>0 - era (G)</li> + * <li>1 - year (y)</li> + * <li>2 - month (M)</li> + * <li>3 - day of month (d)</li> + * <li>4 - hour out of 12, from 1-12 (h)</li> + * <li>5 - hour out of 24, from 0-23 (H)</li> + * <li>6 - minute (m)</li> + * <li>7 - second (s)</li> + * <li>8 - millisecond (S)</li> + * <li>9 - date of week (E)</li> + * <li>10 - date of year (D)</li> + * <li>11 - day of week in month, eg. "4th Thur in Nov" (F)</li> + * <li>12 - week in year (w)</li> + * <li>13 - week in month (W)</li> + * <li>14 - am/pm (a)</li> + * <li>15 - hour out of 24, from 1-24 (k)</li> + * <li>16 - hour out of 12, from 0-11 (K)</li> + * <li>17 - time zone (z)</li> + * </ul> + * + * @return The format patter characters + */ + public String getLocalPatternChars() + { + return localPatternChars; + } + + /** + * This method returns the list of strings used for displaying month + * names (e.g., "January" and "February"). This is a thirteen element + * string array indexed by <code>Calendar.JANUARY</code> through + * <code>Calendar.UNDECEMBER</code>. Note that there are thirteen + * elements because some calendars have thriteen months. + * + * @return The list of month display strings. + */ + public String[] getMonths () + { + return months; + } + + /** + * This method returns the list of strings used for displaying abbreviated + * month names (e.g., "Jan" and "Feb"). This is a thirteen element + * <code>String</code> array indexed by <code>Calendar.JANUARY</code> + * through <code>Calendar.UNDECEMBER</code>. Note that there are thirteen + * elements because some calendars have thirteen months. + * + * @return The list of abbreviated month display strings. + */ + public String[] getShortMonths () + { + return shortMonths; + } + + /** + * This method returns the list of strings used for displaying abbreviated + * weekday names (e.g., "Sun" and "Mon"). This is an eight element + * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> + * through <code>Calendar.SATURDAY</code>. Note that the first element + * of this array is ignored. + * + * @return This list of abbreviated weekday display strings. + */ + public String[] getShortWeekdays () + { + return shortWeekdays; + } + + /** + * This method returns the list of strings used for displaying weekday + * names (e.g., "Sunday" and "Monday"). This is an eight element + * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> + * through <code>Calendar.SATURDAY</code>. Note that the first element + * of this array is ignored. + * + * @return This list of weekday display strings. + */ + public String[] getWeekdays () + { + return weekdays; + } + + /** + * This method returns this list of localized timezone display strings. + * This is a two dimensional <code>String</code> array where each row in + * the array contains five values: + * <P> + * <ul> + * <li>0 - The non-localized time zone id string.</li> + * <li>1 - The long name of the time zone (standard time).</li> + * <li>2 - The short name of the time zone (standard time).</li> + * <li>3 - The long name of the time zone (daylight savings time).</li> + * <li>4 - the short name of the time zone (daylight savings time).</li> + * </ul> + * + * @return The list of time zone display strings. + */ + public String[] [] getZoneStrings () + { + return zoneStrings; + } + + /** + * This method sets the list of strings used to display AM/PM values to + * the specified list. + * This is a two element <code>String</code> array indexed by + * <code>Calendar.AM</code> and <code>Calendar.PM</code> + * + * @param value The new list of AM/PM display strings. + */ + public void setAmPmStrings (String[] value) + { + ampms = value; + } + + /** + * This method sets the list of strings used to display time eras to + * to the specified list. + * This is a two element <code>String</code> + * array indexed by <code>Calendar.BC</code> and <code>Calendar.AD</code>. + * + * @param labels The new list of era display strings. + */ + public void setEras (String[] labels) + { + eras = labels; + } + + /** + * This method sets the list of characters used to specific date/time + * formatting strings. + * This is an 18 character string that contains the characters + * that are used in creating the date formatting strings in + * <code>SimpleDateFormat</code>. The following are the character + * positions in the string and which format character they correspond + * to (the character in parentheses is the default value in the US English + * locale): + * <p> + * <ul> + * <li>0 - era (G)</li> + * <li>1 - year (y)</li> + * <li>2 - month (M)</li> + * <li>3 - day of month (d)</li> + * <li>4 - hour out of 12, from 1-12 (h)</li> + * <li>5 - hour out of 24, from 0-23 (H)</li> + * <li>6 - minute (m)</li> + * <li>7 - second (s)</li> + * <li>8 - millisecond (S)</li> + * <li>9 - date of week (E)</li> + * <li>10 - date of year (D)</li> + * <li>11 - day of week in month, eg. "4th Thur in Nov" (F)</li> + * <li>12 - week in year (w)</li> + * <li>13 - week in month (W)</li> + * <li>14 - am/pm (a)</li> + * <li>15 - hour out of 24, from 1-24 (k)</li> + * <li>16 - hour out of 12, from 0-11 (K)</li> + * <li>17 - time zone (z)</li> + * </ul> + * + * @param chars The new format pattern characters + */ + public void setLocalPatternChars (String chars) + { + localPatternChars = chars; + } + + /** + * This method sets the list of strings used to display month names. + * This is a thirteen element + * string array indexed by <code>Calendar.JANUARY</code> through + * <code>Calendar.UNDECEMBER</code>. Note that there are thirteen + * elements because some calendars have thriteen months. + * + * @param labels The list of month display strings. + */ + public void setMonths (String[] labels) + { + months = labels; + } + + /** + * This method sets the list of strings used to display abbreviated month + * names. + * This is a thirteen element + * <code>String</code> array indexed by <code>Calendar.JANUARY</code> + * through <code>Calendar.UNDECEMBER</code>. Note that there are thirteen + * elements because some calendars have thirteen months. + * + * @param labels The new list of abbreviated month display strings. + */ + public void setShortMonths (String[] labels) + { + shortMonths = labels; + } + + /** + * This method sets the list of strings used to display abbreviated + * weekday names. + * This is an eight element + * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> + * through <code>Calendar.SATURDAY</code>. Note that the first element + * of this array is ignored. + * + * @param labels This list of abbreviated weekday display strings. + */ + public void setShortWeekdays (String[] labels) + { + shortWeekdays = labels; + } + + /** + * This method sets the list of strings used to display weekday names. + * This is an eight element + * <code>String</code> array indexed by <code>Calendar.SUNDAY</code> + * through <code>Calendar.SATURDAY</code>. Note that the first element + * of this array is ignored. + * + * @param labels This list of weekday display strings. + */ + public void setWeekdays (String[] labels) + { + weekdays = labels; + } + + /** + * This method sets the list of display strings for time zones. + * This is a two dimensional <code>String</code> array where each row in + * the array contains five values: + * <P> + * <ul> + * <li>0 - The non-localized time zone id string.</li> + * <li>1 - The long name of the time zone (standard time).</li> + * <li>2 - The short name of the time zone (standard time).</li> + * <li>3 - The long name of the time zone (daylight savings time).</li> + * <li>4 - the short name of the time zone (daylight savings time).</li> + * </ul> + * + * @params zones The list of time zone display strings. + */ + public void setZoneStrings (String[][] zones) + { + zoneStrings = zones; + } + + /* Does a "deep" equality test - recurses into arrays. */ + private static boolean equals (Object x, Object y) + { + if (x == y) + return true; + if (x == null || y == null) + return false; + if (! (x instanceof Object[]) || ! (y instanceof Object[])) + return x.equals(y); + Object[] xa = (Object[]) x; + Object[] ya = (Object[]) y; + if (xa.length != ya.length) + return false; + for (int i = xa.length; --i >= 0; ) + { + if (! equals(xa[i], ya[i])) + return false; + } + return true; + } + + private static int hashCode (Object x) + { + if (x == null) + return 0; + if (! (x instanceof Object[])) + return x.hashCode(); + Object[] xa = (Object[]) x; + int hash = 0; + for (int i = 0; i < xa.length; i++) + hash = 37 * hashCode(xa[i]); + return hash; + } + + /** + * This method tests a specified object for equality against this object. + * This will be true if and only if the specified object: + * <p> + * <ul> + * <li> Is not <code>null</code>.</li> + * <li> Is an instance of <code>DateFormatSymbols</code>.</li> + * <li> Contains identical formatting symbols to this object.</li> + * </ul> + * + * @param obj The <code>Object</code> to test for equality against. + * + * @return <code>true</code> if the specified object is equal to this one, + * <code>false</code> otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof DateFormatSymbols)) + return false; + DateFormatSymbols other = (DateFormatSymbols) obj; + return (equals(ampms, other.ampms) + && equals(eras, other.eras) + && equals(localPatternChars, other.localPatternChars) + && equals(months, other.months) + && equals(shortMonths, other.shortMonths) + && equals(shortWeekdays, other.shortWeekdays) + && equals(weekdays, other.weekdays) + && equals(zoneStrings, other.zoneStrings)); + } + + /** + * Returns a new copy of this object. + * + * @return A copy of this object + */ + public Object clone () + { + try + { + return super.clone (); + } + catch (CloneNotSupportedException e) + { + return null; + } + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode () + { + return (hashCode(ampms) + ^ hashCode(eras) + ^ hashCode(localPatternChars) + ^ hashCode(months) + ^ hashCode(shortMonths) + ^ hashCode(shortWeekdays) + ^ hashCode(weekdays) + ^ hashCode(zoneStrings)); + } +} diff --git a/gcc-4.2.1/libjava/java/text/DecimalFormatSymbols.java b/gcc-4.2.1/libjava/java/text/DecimalFormatSymbols.java new file mode 100644 index 000000000..c58530fc5 --- /dev/null +++ b/gcc-4.2.1/libjava/java/text/DecimalFormatSymbols.java @@ -0,0 +1,613 @@ +/* DecimalFormatSymbols.java -- Format symbols used by DecimalFormat + Copyright (C) 1999, 2000, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.text; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.Serializable; +import java.util.Currency; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * This class is a container for the symbols used by + * <code>DecimalFormat</code> to format numbers and currency. These are + * normally handled automatically, but an application can override + * values as desired using this class. + * + * @author Tom Tromey (tromey@cygnus.com) + * @author Aaron M. Renn (arenn@urbanophile.com) + * @date February 24, 1999 + */ +/* Written using "Java Class Libraries", 2nd edition, plus online + * API docs for JDK 1.2 from http://www.javasoft.com. + * Status: Believed complete and correct to 1.2. + */ +public final class DecimalFormatSymbols implements Cloneable, Serializable +{ + public Object clone () + { + try + { + return super.clone (); + } + catch(CloneNotSupportedException e) + { + return null; + } + } + + /** + * This method initializes a new instance of + * <code>DecimalFormatSymbols</code> for the default locale. + */ + public DecimalFormatSymbols () + { + this (Locale.getDefault()); + } + + private String safeGetString(ResourceBundle bundle, + String name, String def) + { + if (bundle != null) + { + try + { + return bundle.getString(name); + } + catch (MissingResourceException x) + { + } + } + return def; + } + + private char safeGetChar(ResourceBundle bundle, + String name, char def) + { + String r = null; + if (bundle != null) + { + try + { + r = bundle.getString(name); + } + catch (MissingResourceException x) + { + } + } + if (r == null || r.length() < 1) + return def; + return r.charAt(0); + } + + /** + * This method initializes a new instance of + * <code>DecimalFormatSymbols</code> for the specified locale. + * + * @param loc The local to load symbols for. + */ + public DecimalFormatSymbols (Locale loc) + { + ResourceBundle res; + try + { + res = ResourceBundle.getBundle("gnu.java.locale.LocaleInformation", + loc, ClassLoader.getSystemClassLoader()); + } + catch (MissingResourceException x) + { + res = null; + } + currencySymbol = safeGetString (res, "currencySymbol", "$"); + decimalSeparator = safeGetChar (res, "decimalSeparator", '.'); + digit = safeGetChar (res, "digit", '#'); + exponential = safeGetChar (res, "exponential", 'E'); + groupingSeparator = safeGetChar (res, "groupingSeparator", ','); + infinity = safeGetString (res, "infinity", "\u221e"); + // FIXME: default? + intlCurrencySymbol = safeGetString (res, "intlCurrencySymbol", "$"); + try + { + monetarySeparator = safeGetChar (res, "monetarySeparator", '.'); + } + catch (MissingResourceException x) + { + monetarySeparator = decimalSeparator; + } + minusSign = safeGetChar (res, "minusSign", '-'); + NaN = safeGetString (res, "NaN", "\ufffd"); + patternSeparator = safeGetChar (res, "patternSeparator", ';'); + percent = safeGetChar (res, "percent", '%'); + perMill = safeGetChar (res, "perMill", '\u2030'); + zeroDigit = safeGetChar (res, "zeroDigit", '0'); + locale = loc; + } + + /** + * This method this this object for equality against the specified object. + * This will be true if and only if the following criteria are met with + * regard to the specified object: + * <p> + * <ul> + * <li>It is not <code>null</code>.</li> + * <li>It is an instance of <code>DecimalFormatSymbols</code>.</li> + * <li>All of its symbols are identical to the symbols in this object.</li> + * </ul> + * + * @return <code>true</code> if the specified object is equal to this + * object, <code>false</code> otherwise. + */ + public boolean equals (Object obj) + { + if (! (obj instanceof DecimalFormatSymbols)) + return false; + DecimalFormatSymbols dfs = (DecimalFormatSymbols) obj; + return (currencySymbol.equals(dfs.currencySymbol) + && decimalSeparator == dfs.decimalSeparator + && digit == dfs.digit + && exponential == dfs.exponential + && groupingSeparator == dfs.groupingSeparator + && infinity.equals(dfs.infinity) + && intlCurrencySymbol.equals(dfs.intlCurrencySymbol) + && minusSign == dfs.minusSign + && monetarySeparator == dfs.monetarySeparator + && NaN.equals(dfs.NaN) + && patternSeparator == dfs.patternSeparator + && percent == dfs.percent + && perMill == dfs.perMill + && zeroDigit == dfs.zeroDigit); + } + + /** + * Returns the currency corresponding to the currency symbol stored + * in the instance of <code>DecimalFormatSymbols</code>. + * + * @return A new instance of <code>Currency</code> if + * the currency code matches a known one. + */ + public Currency getCurrency () + { + return Currency.getInstance (currencySymbol); + } + + /** + * This method returns the currency symbol in local format. For example, + * "$" for Canadian dollars. + * + * @return The currency symbol in local format. + */ + public String getCurrencySymbol () + { + return currencySymbol; + } + + /** + * This method returns the character used as the decimal point. + * + * @return The character used as the decimal point. + */ + public char getDecimalSeparator () + { + return decimalSeparator; + } + + /** + * This method returns the character used to represent a digit in a + * format pattern string. + * + * @return The character used to represent a digit in a format + * pattern string. + */ + public char getDigit () + { + return digit; + } + + // This is our own extension. + char getExponential () + { + return exponential; + } + + /** + * This method sets the character used to separate groups of digits. For + * example, the United States uses a comma (,) to separate thousands in + * a number. + * + * @return The character used to separate groups of digits. + */ + public char getGroupingSeparator () + { + return groupingSeparator; + } + + /** + * This method returns the character used to represent infinity. + * + * @return The character used to represent infinity. + */ + public String getInfinity () + { + return infinity; + } + + /** + * This method returns the currency symbol in international format. For + * example, "C$" for Canadian dollars. + * + * @return The currency symbol in international format. + */ + public String getInternationalCurrencySymbol () + { + return intlCurrencySymbol; + } + + /** + * This method returns the character used to represent the minus sign. + * + * @return The character used to represent the minus sign. + */ + public char getMinusSign () + { + return minusSign; + } + + /** + * This method returns the character used to represent the decimal + * point for currency values. + * + * @return The decimal point character used in currency values. + */ + public char getMonetaryDecimalSeparator () + { + return monetarySeparator; + } + + /** + * This method returns the string used to represent the NaN (not a number) + * value. + * + * @return The string used to represent NaN + */ + public String getNaN () + { + return NaN; + } + + /** + * This method returns the character used to separate positive and negative + * subpatterns in a format pattern. + * + * @return The character used to separate positive and negative subpatterns + * in a format pattern. + */ + public char getPatternSeparator () + { + return patternSeparator; + } + + /** + * This method returns the character used as the percent sign. + * + * @return The character used as the percent sign. + */ + public char getPercent () + { + return percent; + } + + /** + * This method returns the character used as the per mille character. + * + * @return The per mille character. + */ + public char getPerMill () + { + return perMill; + } + + /** + * This method returns the character used to represent the digit zero. + * + * @return The character used to represent the digit zero. + */ + public char getZeroDigit () + { + return zeroDigit; + } + + /** + * This method returns a hash value for this object. + * + * @return A hash value for this object. + */ + public int hashCode () + { + // Compute based on zero digit, grouping separator, and decimal + // separator -- JCL book. This probably isn't a very good hash + // code. + return zeroDigit << 16 + groupingSeparator << 8 + decimalSeparator; + } + + /** + * This method sets the currency to the specified value. + * + * @param currency The new currency + */ + public void setCurrency (Currency currency) + { + setCurrencySymbol (currency.getSymbol()); + } + + /** + * This method sets the currency symbol to the specified value. + * + * @param currency The new currency symbol + */ + public void setCurrencySymbol (String currency) + { + currencySymbol = currency; + } + + /** + * This method sets the decimal point character to the specified value. + * + * @param decimalSep The new decimal point character + */ + public void setDecimalSeparator (char decimalSep) + { + decimalSeparator = decimalSep; + } + + /** + * This method sets the character used to represents a digit in a format + * string to the specified value. + * + * @param digit The character used to represent a digit in a format pattern. + */ + public void setDigit (char digit) + { + this.digit = digit; + } + + // This is our own extension. + void setExponential (char exp) + { + exponential = exp; + } + + /** + * This method sets the character used to separate groups of digits. + * + * @param groupSep The character used to separate groups of digits. + */ + public void setGroupingSeparator (char groupSep) + { + groupingSeparator = groupSep; + } + + /** + * This method sets the string used to represents infinity. + * + * @param infinity The string used to represent infinity. + */ + public void setInfinity (String infinity) + { + this.infinity = infinity; + } + + /** + * This method sets the international currency symbols to the + * specified value. + * + * @param intlCurrencySymbol The new international currency symbol. + */ + public void setInternationalCurrencySymbol (String currency) + { + intlCurrencySymbol = currency; + } + + /** + * This method sets the character used to represent the minus sign. + * + * @param minusSign The character used to represent the minus sign. + */ + public void setMinusSign (char minusSign) + { + this.minusSign = minusSign; + } + + /** + * This method sets the character used for the decimal point in currency + * values. + * + * @param decimalSep The decimal point character used in currency values. + */ + public void setMonetaryDecimalSeparator (char decimalSep) + { + monetarySeparator = decimalSep; + } + + /** + * This method sets the string used to represent the NaN (not a + * number) value. + * + * @param nan The string used to represent NaN + */ + public void setNaN (String nan) + { + NaN = nan; + } + + /** + * This method sets the character used to separate positive and negative + * subpatterns in a format pattern. + * + * @param patternSep The character used to separate positive and + * negative subpatterns in a format pattern. + */ + public void setPatternSeparator (char patternSep) + { + patternSeparator = patternSep; + } + + /** + * This method sets the character used as the percent sign. + * + * @param percent The character used as the percent sign. + */ + public void setPercent (char percent) + { + this.percent = percent; + } + + /** + * This method sets the character used as the per mille character. + * + * @param perMill The per mille character. + */ + public void setPerMill (char perMill) + { + this.perMill = perMill; + } + + /** + * This method sets the character used to represent the digit zero. + * + * @param zeroDigit The character used to represent the digit zero. + */ + public void setZeroDigit (char zeroDigit) + { + this.zeroDigit = zeroDigit; + } + + /** + * @serial A string used for the local currency + */ + private String currencySymbol; + /** + * @serial The <code>char</code> used to separate decimals in a number. + */ + private char decimalSeparator; + /** + * @serial This is the <code>char</code> used to represent a digit in + * a format specification. + */ + private char digit; + /** + * @serial This is the <code>char</code> used to represent the exponent + * separator in exponential notation. + */ + private char exponential; + /** + * @serial This separates groups of thousands in numbers. + */ + private char groupingSeparator; + /** + * @serial This string represents infinity. + */ + private String infinity; + /** + * @serial This string represents the local currency in an international + * context, eg, "C$" for Canadian dollars. + */ + private String intlCurrencySymbol; + /** + * @serial This is the character used to represent the minus sign. + */ + private char minusSign; + /** + * @serial This character is used to separate decimals when formatting + * currency values. + */ + private char monetarySeparator; + /** + * @serial This string is used the represent the Java NaN value for + * "not a number". + */ + private String NaN; + /** + * @serial This is the character used to separate positive and negative + * subpatterns in a format pattern. + */ + private char patternSeparator; + /** + * @serial This is the percent symbols + */ + private char percent; + /** + * @serial This character is used for the mille percent sign. + */ + private char perMill; + /** + * @serial This value represents the type of object being de-serialized. + * 0 indicates a pre-Java 1.1.6 version, 1 indicates 1.1.6 or later. + * 0 indicates a pre-Java 1.1.6 version, 1 indicates 1.1.6 or later, + * 2 indicates 1.4 or later + */ + private int serialVersionOnStream = 2; + /** + * @serial This is the character used to represent 0. + */ + private char zeroDigit; + + /** + * @serial The locale of these currency symbols. + */ + private Locale locale; + + private static final long serialVersionUID = 5772796243397350300L; + + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (serialVersionOnStream < 1) + { + monetarySeparator = decimalSeparator; + exponential = 'E'; + } + if (serialVersionOnStream < 2) + locale = Locale.getDefault(); + + serialVersionOnStream = 2; + } +} diff --git a/gcc-4.2.1/libjava/java/text/natCollator.cc b/gcc-4.2.1/libjava/java/text/natCollator.cc new file mode 100644 index 000000000..676a4a41a --- /dev/null +++ b/gcc-4.2.1/libjava/java/text/natCollator.cc @@ -0,0 +1,74 @@ +// natCollator.cc - Native code for collation. + +/* Copyright (C) 1999 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@cygnus.com>. + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/text/Collator.h> +#include <java/lang/StringBuffer.h> + +#include <java-chardecomp.h> + +void +java::text::Collator::decomposeCharacter (jchar c, + java::lang::StringBuffer *buf) +{ + if (decmp == NO_DECOMPOSITION) + { + buf->append(c); + return; + } + + const struct decomp_entry *base; + int high; + + if (decmp == FULL_DECOMPOSITION) + { + base = full_decomposition; + high = sizeof (full_decomposition) / sizeof (struct decomp_entry); + } + else + { + base = canonical_decomposition; + high = sizeof (canonical_decomposition) / sizeof (struct decomp_entry); + } + + // FIXME: this is probably a bit slow for the task at hand. + int i = high / 2; + int low = 0; + while (true) + { + if (c < base[i].key) + high = i; + else if (c > base[i].key) + low = i; + else + break; + + int old = i; + i = (high + low) / 2; + if (i == old) + { + // Not in table, so it expands to itself. + buf->append(c); + return; + } + } + + for (int j = 0; base[i].value[j] != '\0'; j += 2) + { + jchar x = (base[i].value[j] << 8) | (base[i].value[j + 1]); + buf->append (x); + } +} diff --git a/gcc-4.2.1/libjava/java/util/Calendar.java b/gcc-4.2.1/libjava/java/util/Calendar.java new file mode 100644 index 000000000..5559d8c53 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/Calendar.java @@ -0,0 +1,1277 @@ +/* Calendar.java -- + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +/** + * This class is an abstract base class for Calendars, which can be + * used to convert between <code>Date</code> objects and a set of + * integer fields which represent <code>YEAR</code>, + * <code>MONTH</code>, <code>DAY</code>, etc. The <code>Date</code> + * object represents a time in milliseconds since the Epoch. <br> + * + * This class is locale sensitive. To get the Object matching the + * current locale you can use <code>getInstance</code>. You can even provide + * a locale or a timezone. <code>getInstance</code> returns currently + * a <code>GregorianCalendar</code> for the current date. <br> + * + * If you want to convert a date from the Year, Month, Day, DayOfWeek, + * etc. Representation to a <code>Date</code>-Object, you can create + * a new Calendar with <code>getInstance()</code>, + * <code>clear()</code> all fields, <code>set(int,int)</code> the + * fields you need and convert it with <code>getTime()</code>. <br> + * + * If you want to convert a <code>Date</code>-object to the Calendar + * representation, create a new Calendar, assign the + * <code>Date</code>-Object with <code>setTime()</code>, and read the + * fields with <code>get(int)</code>. <br> + * + * When computing the date from time fields, it may happen, that there + * are either two few fields set, or some fields are inconsistent. This + * cases will handled in a calendar specific way. Missing fields are + * replaced by the fields of the epoch: 1970 January 1 00:00. <br> + * + * To understand, how the day of year is computed out of the fields + * look at the following table. It is traversed from top to bottom, + * and for the first line all fields are set, that line is used to + * compute the day. <br> + * + * +<pre>month + day_of_month +month + week_of_month + day_of_week +month + day_of_week_of_month + day_of_week +day_of_year +day_of_week + week_of_year</pre> + * + * The hour_of_day-field takes precedence over the ampm and + * hour_of_ampm fields. <br> + * + * <STRONG>Note:</STRONG> This can differ for non-Gregorian calendar. <br> + * + * To convert a calendar to a human readable form and vice versa, use + * the <code>java.text.DateFormat</code> class. <br> + * + * Other useful things you can do with an calendar, is + * <code>roll</code>ing fields (that means increase/decrease a + * specific field by one, propagating overflows), or + * <code>add</code>ing/substracting a fixed amount to a field. + * + * @see Date + * @see GregorianCalendar + * @see TimeZone + * @see java.text.DateFormat + */ +public abstract class Calendar implements Serializable, Cloneable +{ + /** + * Constant representing the era time field. + */ + public static final int ERA = 0; + + /** + * Constant representing the year time field. + */ + public static final int YEAR = 1; + + /** + * Constant representing the month time field. This field + * should contain one of the JANUARY,...,DECEMBER constants below. + */ + public static final int MONTH = 2; + + /** + * Constant representing the week of the year field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_YEAR = 3; + + /** + * Constant representing the week of the month time field. + * @see #setFirstDayOfWeek(int) + */ + public static final int WEEK_OF_MONTH = 4; + + /** + * Constant representing the day time field, synonym for DAY_OF_MONTH. + */ + public static final int DATE = 5; + + /** + * Constant representing the day time field. + */ + public static final int DAY_OF_MONTH = 5; + + /** + * Constant representing the day of year time field. This is + * 1 for the first day in month. + */ + public static final int DAY_OF_YEAR = 6; + + /** + * Constant representing the day of week time field. This field + * should contain one of the SUNDAY,...,SATURDAY constants below. + */ + public static final int DAY_OF_WEEK = 7; + + /** + * Constant representing the day-of-week-in-month field. For + * instance this field contains 2 for the second thursday in a + * month. If you give a negative number here, the day will count + * from the end of the month. + */ + public static final int DAY_OF_WEEK_IN_MONTH = 8; + + /** + * Constant representing the part of the day for 12-hour clock. This + * should be one of AM or PM. + */ + public static final int AM_PM = 9; + + /** + * Constant representing the hour time field for 12-hour clock. + */ + public static final int HOUR = 10; + + /** + * Constant representing the hour of day time field for 24-hour clock. + */ + public static final int HOUR_OF_DAY = 11; + + /** + * Constant representing the minute of hour time field. + */ + public static final int MINUTE = 12; + + /** + * Constant representing the second time field. + */ + public static final int SECOND = 13; + + /** + * Constant representing the millisecond time field. + */ + public static final int MILLISECOND = 14; + + /** + * Constant representing the time zone offset time field for the + * time given in the other fields. It is measured in + * milliseconds. The default is the offset of the time zone. + */ + public static final int ZONE_OFFSET = 15; + + /** + * Constant representing the daylight saving time offset in + * milliseconds. The default is the value given by the time zone. + */ + public static final int DST_OFFSET = 16; + + /** + * Number of time fields. + */ + public static final int FIELD_COUNT = 17; + + /** + * Constant representing Sunday. + */ + public static final int SUNDAY = 1; + + /** + * Constant representing Monday. + */ + public static final int MONDAY = 2; + + /** + * Constant representing Tuesday. + */ + public static final int TUESDAY = 3; + + /** + * Constant representing Wednesday. + */ + public static final int WEDNESDAY = 4; + + /** + * Constant representing Thursday. + */ + public static final int THURSDAY = 5; + + /** + * Constant representing Friday. + */ + public static final int FRIDAY = 6; + + /** + * Constant representing Saturday. + */ + public static final int SATURDAY = 7; + + /** + * Constant representing January. + */ + public static final int JANUARY = 0; + + /** + * Constant representing February. + */ + public static final int FEBRUARY = 1; + + /** + * Constant representing March. + */ + public static final int MARCH = 2; + + /** + * Constant representing April. + */ + public static final int APRIL = 3; + + /** + * Constant representing May. + */ + public static final int MAY = 4; + + /** + * Constant representing June. + */ + public static final int JUNE = 5; + + /** + * Constant representing July. + */ + public static final int JULY = 6; + + /** + * Constant representing August. + */ + public static final int AUGUST = 7; + + /** + * Constant representing September. + */ + public static final int SEPTEMBER = 8; + + /** + * Constant representing October. + */ + public static final int OCTOBER = 9; + + /** + * Constant representing November. + */ + public static final int NOVEMBER = 10; + + /** + * Constant representing December. + */ + public static final int DECEMBER = 11; + + /** + * Constant representing Undecimber. This is an artificial name useful + * for lunar calendars. + */ + public static final int UNDECIMBER = 12; + + /** + * Useful constant for 12-hour clock. + */ + public static final int AM = 0; + + /** + * Useful constant for 12-hour clock. + */ + public static final int PM = 1; + + /** + * The time fields. The array is indexed by the constants YEAR to + * DST_OFFSET. + * @serial + */ + protected int[] fields = new int[FIELD_COUNT]; + + /** + * The flags which tell if the fields above have a value. + * @serial + */ + protected boolean[] isSet = new boolean[FIELD_COUNT]; + + /** + * The time in milliseconds since the epoch. + * @serial + */ + protected long time; + + /** + * Tells if the above field has a valid value. + * @serial + */ + protected boolean isTimeSet; + + /** + * Tells if the fields have a valid value. This superseeds the isSet + * array. + * @serial + */ + protected boolean areFieldsSet; + + /** + * The time zone of this calendar. Used by sub classes to do UTC / local + * time conversion. Sub classes can access this field with getTimeZone(). + * @serial + */ + private TimeZone zone; + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @serial + */ + private boolean lenient; + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @serial + */ + private int firstDayOfWeek; + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @serial + */ + private int minimalDaysInFirstWeek; + + /** + * Is set to true if DST_OFFSET is explicitly set. In that case + * it's value overrides the value computed from the current + * time and the timezone. + */ + private boolean explicitDSTOffset = false; + + /** + * The version of the serialized data on the stream. + * <dl><dt>0 or not present</dt> + * <dd> JDK 1.1.5 or later.</dd> + * <dt>1</dt> + * <dd>JDK 1.1.6 or later. This always writes a correct `time' value + * on the stream, as well as the other fields, to be compatible with + * earlier versions</dd></dl> + * @since JDK1.1.6 + * @serial + */ + private int serialVersionOnStream = 1; + + /** + * XXX - I have not checked the compatibility. The documentation of + * the serialized-form is quite hairy... + */ + static final long serialVersionUID = -1807547505821590642L; + + /** + * The name of the resource bundle. Used only by getBundle() + */ + private static final String bundleName = "gnu.java.locale.Calendar"; + + /** + * get resource bundle: + * The resources should be loaded via this method only. Iff an application + * uses this method, the resourcebundle is required. + */ + private static ResourceBundle getBundle(Locale locale) + { + return ResourceBundle.getBundle(bundleName, locale, + ClassLoader.getSystemClassLoader()); + } + + /** + * Constructs a new Calendar with the default time zone and the default + * locale. + */ + protected Calendar() + { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Constructs a new Calendar with the given time zone and the given + * locale. + * @param zone a time zone. + * @param locale a locale. + */ + protected Calendar(TimeZone zone, Locale locale) + { + this.zone = zone; + lenient = true; + + ResourceBundle rb = getBundle(locale); + + firstDayOfWeek = ((Integer) rb.getObject("firstDayOfWeek")).intValue(); + minimalDaysInFirstWeek = ((Integer) rb.getObject("minimalDaysInFirstWeek")) + .intValue(); + clear(); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and locale. + */ + public static synchronized Calendar getInstance() + { + return getInstance(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the given + * time zone and the default locale. + * @param zone a time zone. + */ + public static synchronized Calendar getInstance(TimeZone zone) + { + return getInstance(zone, Locale.getDefault()); + } + + /** + * Creates a calendar representing the actual time, using the default + * time zone and the given locale. + * @param locale a locale. + */ + public static synchronized Calendar getInstance(Locale locale) + { + return getInstance(TimeZone.getDefault(), locale); + } + + /** + * Cache of locale->calendar-class mappings. This avoids having to do a ResourceBundle + * lookup for every getInstance call. + */ + private static HashMap cache = new HashMap(); + + /** Preset argument types for calendar-class constructor lookup. */ + private static Class[] ctorArgTypes = new Class[] + { + TimeZone.class, Locale.class + }; + + /** + * Creates a calendar representing the actual time, using the given + * time zone and locale. + * @param zone a time zone. + * @param locale a locale. + */ + public static synchronized Calendar getInstance(TimeZone zone, Locale locale) + { + Class calendarClass = (Class) cache.get(locale); + Throwable exception = null; + + try + { + if (calendarClass == null) + { + ResourceBundle rb = getBundle(locale); + String calendarClassName = rb.getString("calendarClass"); + + if (calendarClassName != null) + { + calendarClass = Class.forName(calendarClassName); + if (Calendar.class.isAssignableFrom(calendarClass)) + cache.put(locale, calendarClass); + } + } + + // GregorianCalendar is by far the most common case. Optimize by + // avoiding reflection. + if (calendarClass == GregorianCalendar.class) + return new GregorianCalendar(zone, locale); + + if (Calendar.class.isAssignableFrom(calendarClass)) + { + Constructor ctor = calendarClass.getConstructor(ctorArgTypes); + return (Calendar) ctor.newInstance(new Object[] { zone, locale }); + } + } + catch (ClassNotFoundException ex) + { + exception = ex; + } + catch (IllegalAccessException ex) + { + exception = ex; + } + catch (NoSuchMethodException ex) + { + exception = ex; + } + catch (InstantiationException ex) + { + exception = ex; + } + catch (InvocationTargetException ex) + { + exception = ex; + } + + throw new RuntimeException("Error instantiating calendar for locale " + + locale, exception); + } + + /** + * Gets the set of locales for which a Calendar is available. + * @exception MissingResourceException if locale data couldn't be found. + * @return the set of locales. + */ + public static synchronized Locale[] getAvailableLocales() + { + ResourceBundle rb = getBundle(new Locale("", "")); + return (Locale[]) rb.getObject("availableLocales"); + } + + /** + * Converts the time field values (<code>fields</code>) to + * milliseconds since the epoch UTC (<code>time</code>). Override + * this method if you write your own Calendar. */ + protected abstract void computeTime(); + + /** + * Converts the milliseconds since the epoch UTC + * (<code>time</code>) to time fields + * (<code>fields</code>). Override this method if you write your + * own Calendar. + */ + protected abstract void computeFields(); + + /** + * Converts the time represented by this object to a + * <code>Date</code>-Object. + * @return the Date. + */ + public final Date getTime() + { + if (! isTimeSet) + computeTime(); + return new Date(time); + } + + /** + * Sets this Calendar's time to the given Date. All time fields + * are invalidated by this method. + */ + public final void setTime(Date date) + { + setTimeInMillis(date.getTime()); + } + + /** + * Returns the time represented by this Calendar. + * @return the time in milliseconds since the epoch. + * @specnote This was made public in 1.4. + */ + public long getTimeInMillis() + { + if (! isTimeSet) + computeTime(); + return time; + } + + /** + * Sets this Calendar's time to the given Time. All time fields + * are invalidated by this method. + * @param time the time in milliseconds since the epoch + * @specnote This was made public in 1.4. + */ + public void setTimeInMillis(long time) + { + clear(); + this.time = time; + isTimeSet = true; + computeFields(); + } + + /** + * Gets the value of the specified field. They are recomputed + * if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + * @specnote Not final since JDK 1.4 + */ + public int get(int field) + { + // If the requested field is invalid, force all fields to be recomputed. + if (! isSet[field]) + areFieldsSet = false; + complete(); + return fields[field]; + } + + /** + * Gets the value of the specified field. This method doesn't + * recompute the fields, if they are invalid. + * @param field the time field. One of the time field constants. + * @return the value of the specified field, undefined if + * <code>areFieldsSet</code> or <code>isSet[field]</code> is false. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + */ + protected final int internalGet(int field) + { + return fields[field]; + } + + /** + * Sets the time field with the given value. This does invalidate + * the time in milliseconds. + * @param field the time field. One of the time field constants + * @param value the value to be set. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + * @specnote Not final since JDK 1.4 + */ + public void set(int field, int value) + { + if (isTimeSet) + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + isTimeSet = false; + fields[field] = value; + isSet[field] = true; + + // The five valid date patterns, in order of priority + // 1 YEAR + MONTH + DAY_OF_MONTH + // 2 YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + // 3 YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + // 4 YEAR + DAY_OF_YEAR + // 5 YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + switch (field) + { + case MONTH: // pattern 1,2 or 3 + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: // pattern 1 + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[WEEK_OF_MONTH] = true; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case WEEK_OF_MONTH: // pattern 2 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_WEEK_IN_MONTH: // pattern 3 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[MONTH] = true; + isSet[DAY_OF_WEEK] = true; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_YEAR: // pattern 4 + isSet[YEAR] = true; + isSet[MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case WEEK_OF_YEAR: // pattern 5 + if (! isSet[DAY_OF_WEEK]) + fields[DAY_OF_WEEK] = getFirstDayOfWeek(); + isSet[YEAR] = true; + isSet[DAY_OF_WEEK] = true; + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + break; + case AM_PM: + isSet[HOUR] = true; + isSet[HOUR_OF_DAY] = false; + break; + case HOUR_OF_DAY: + isSet[AM_PM] = false; + isSet[HOUR] = false; + break; + case HOUR: + isSet[AM_PM] = true; + isSet[HOUR_OF_DAY] = false; + break; + case DST_OFFSET: + explicitDSTOffset = true; + } + + // May have crossed over a DST boundary. + if (! explicitDSTOffset && (field != DST_OFFSET && field != ZONE_OFFSET)) + isSet[DST_OFFSET] = false; + } + + /** + * Sets the fields for year, month, and date + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + */ + public final void set(int year, int month, int date) + { + isTimeSet = false; + fields[YEAR] = year; + fields[MONTH] = month; + fields[DATE] = date; + isSet[YEAR] = isSet[MONTH] = isSet[DATE] = true; + isSet[WEEK_OF_YEAR] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[ERA] = false; + + if (! explicitDSTOffset) + isSet[DST_OFFSET] = false; // May have crossed a DST boundary. + } + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + */ + public final void set(int year, int month, int date, int hour, int minute) + { + set(year, month, date); + fields[HOUR_OF_DAY] = hour; + fields[MINUTE] = minute; + isSet[HOUR_OF_DAY] = isSet[MINUTE] = true; + isSet[AM_PM] = false; + isSet[HOUR] = false; + } + + /** + * Sets the fields for year, month, date, hour, and minute + * @param year the year. + * @param month the month, one of the constants JANUARY..UNDICEMBER. + * @param date the day of the month + * @param hour the hour of day. + * @param minute the minute. + * @param second the second. + */ + public final void set(int year, int month, int date, int hour, int minute, + int second) + { + set(year, month, date, hour, minute); + fields[SECOND] = second; + isSet[SECOND] = true; + } + + /** + * Clears the values of all the time fields. + */ + public final void clear() + { + isTimeSet = false; + areFieldsSet = false; + int zoneOffs = zone.getRawOffset(); + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zoneOffs, 0 + }; + fields = tempFields; + for (int i = 0; i < FIELD_COUNT; i++) + isSet[i] = false; + } + + /** + * Clears the values of the specified time field. + * @param field the time field. One of the time field constants. + * @throws ArrayIndexOutOfBoundsException if field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + */ + public final void clear(int field) + { + int[] tempFields = + { + 1, 1970, JANUARY, 1, 1, 1, 1, THURSDAY, 1, AM, 0, 0, 0, + 0, 0, zone.getRawOffset(), 0 + }; + isTimeSet = false; + areFieldsSet = false; + isSet[field] = false; + fields[field] = tempFields[field]; + } + + /** + * Determines if the specified field has a valid value. + * @return true if the specified field has a value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + */ + public final boolean isSet(int field) + { + return isSet[field]; + } + + /** + * Fills any unset fields in the time field list + */ + protected void complete() + { + if (! isTimeSet) + computeTime(); + if (! areFieldsSet) + computeFields(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessary have the same fields). + */ + public boolean equals(Object o) + { + if (! (o instanceof Calendar)) + return false; + Calendar cal = (Calendar) o; + if (getTimeInMillis() == ((Calendar) o).getTimeInMillis() + && cal.getFirstDayOfWeek() == getFirstDayOfWeek() + && cal.isLenient() == isLenient() + && cal.getMinimalDaysInFirstWeek() == getMinimalDaysInFirstWeek()) + { + TimeZone self = getTimeZone(); + TimeZone oth = cal.getTimeZone(); + return self == null ? oth == null : self.equals(oth); + } + return false; + } + + /** + * Returns a hash code for this calendar. + * @return a hash code, which fullfits the general contract of + * <code>hashCode()</code> + */ + public int hashCode() + { + long time = getTimeInMillis(); + int val = (int) ((time & 0xffffffffL) ^ (time >> 32)); + val += (getFirstDayOfWeek() + (isLenient() ? 1230 : 1237) + + getMinimalDaysInFirstWeek()); + TimeZone self = getTimeZone(); + if (self != null) + val ^= self.hashCode(); + return val; + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a smaller time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + public boolean before(Object o) + { + return getTimeInMillis() < ((Calendar) o).getTimeInMillis(); + } + + /** + * Compares the given calendar with this. + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, and this calendar + * represents a bigger time than the calendar o. + * @exception ClassCastException if o is not an calendar. + * @since JDK1.2 you don't need to override this method + */ + public boolean after(Object o) + { + return getTimeInMillis() > ((Calendar) o).getTimeInMillis(); + } + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field the time field. One of the time field constants. + * @param amount the amount of time. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + */ + public abstract void add(int field, int amount); + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value. <br> + * + * <strong>Note:</strong> There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + */ + public abstract void roll(int field, boolean up); + + /** + * Rolls up or down the specified time field by the given amount. + * A negative amount rolls down. The default implementation is + * call <code>roll(int, boolean)</code> for the specified amount. + * + * Subclasses should override this method to do more intuitiv things. + * + * @param field the time field. One of the time field constants. + * @param amount the amount to roll by, positive for rolling up, + * negative for rolling down. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + * @since JDK1.2 + */ + public void roll(int field, int amount) + { + while (amount > 0) + { + roll(field, true); + amount--; + } + while (amount < 0) + { + roll(field, false); + amount++; + } + } + + /** + * Sets the time zone to the specified value. + * @param zone the new time zone + */ + public void setTimeZone(TimeZone zone) + { + this.zone = zone; + } + + /** + * Gets the time zone of this calendar + * @return the current time zone. + */ + public TimeZone getTimeZone() + { + return zone; + } + + /** + * Specifies if the date/time interpretation should be lenient. + * If the flag is set, a date such as "February 30, 1996" will be + * treated as the 29th day after the February 1. If this flag + * is false, such dates will cause an exception. + * @param lenient true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public void setLenient(boolean lenient) + { + this.lenient = lenient; + } + + /** + * Tells if the date/time interpretation is lenient. + * @return true, if the date should be interpreted linient, + * false if it should be interpreted strict. + */ + public boolean isLenient() + { + return lenient; + } + + /** + * Sets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @param value the first day of week. One of SUNDAY to SATURDAY. + */ + public void setFirstDayOfWeek(int value) + { + firstDayOfWeek = value; + } + + /** + * Gets what the first day of week is. This is used for + * WEEK_OF_MONTH and WEEK_OF_YEAR fields. + * @return the first day of week. One of SUNDAY to SATURDAY. + */ + public int getFirstDayOfWeek() + { + return firstDayOfWeek; + } + + /** + * Sets how many days are required in the first week of the year. + * If the first day of the year should be the first week you should + * set this value to 1. If the first week must be a full week, set + * it to 7. + * @param value the minimal days required in the first week. + */ + public void setMinimalDaysInFirstWeek(int value) + { + minimalDaysInFirstWeek = value; + } + + /** + * Gets how many days are required in the first week of the year. + * @return the minimal days required in the first week. + * @see #setMinimalDaysInFirstWeek + */ + public int getMinimalDaysInFirstWeek() + { + return minimalDaysInFirstWeek; + } + + /** + * Gets the smallest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the smallest value. + */ + public abstract int getMinimum(int field); + + /** + * Gets the biggest value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the biggest value. + */ + public abstract int getMaximum(int field); + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + */ + public abstract int getGreatestMinimum(int field); + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. For example this is 28 for DAY_OF_MONTH. + * @param field the time field. One of the time field constants. + * @return the least maximum value. + */ + public abstract int getLeastMaximum(int field); + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + * @since jdk1.2 + */ + public int getActualMinimum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int min = tmp.getGreatestMinimum(field); + int end = tmp.getMinimum(field); + tmp.set(field, min); + for (; min > end; min--) + { + tmp.add(field, -1); // Try to get smaller + if (tmp.get(field) != min - 1) + break; // Done if not successful + } + return min; + } + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + * @throws ArrayIndexOutOfBoundsException if the field is outside + * the valid range. The value of field must be >= 0 and + * <= <code>FIELD_COUNT</code>. + * @since jdk1.2 + */ + public int getActualMaximum(int field) + { + Calendar tmp = (Calendar) clone(); // To avoid restoring state + int max = tmp.getLeastMaximum(field); + int end = tmp.getMaximum(field); + tmp.set(field, max); + for (; max < end; max++) + { + tmp.add(field, 1); + if (tmp.get(field) != max + 1) + break; + } + return max; + } + + /** + * Return a clone of this object. + */ + public Object clone() + { + try + { + Calendar cal = (Calendar) super.clone(); + cal.fields = (int[]) fields.clone(); + cal.isSet = (boolean[]) isSet.clone(); + return cal; + } + catch (CloneNotSupportedException ex) + { + return null; + } + } + + private static final String[] fieldNames = + { + ",ERA=", ",YEAR=", ",MONTH=", + ",WEEK_OF_YEAR=", + ",WEEK_OF_MONTH=", + ",DAY_OF_MONTH=", + ",DAY_OF_YEAR=", ",DAY_OF_WEEK=", + ",DAY_OF_WEEK_IN_MONTH=", + ",AM_PM=", ",HOUR=", + ",HOUR_OF_DAY=", ",MINUTE=", + ",SECOND=", ",MILLISECOND=", + ",ZONE_OFFSET=", ",DST_OFFSET=" + }; + + /** + * Returns a string representation of this object. It is mainly + * for debugging purposes and its content is implementation + * specific. + */ + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append(getClass().getName()).append('['); + sb.append("time="); + if (isTimeSet) + sb.append(time); + else + sb.append("?"); + sb.append(",zone=" + zone); + sb.append(",areFieldsSet=" + areFieldsSet); + for (int i = 0; i < FIELD_COUNT; i++) + { + sb.append(fieldNames[i]); + if (isSet[i]) + sb.append(fields[i]); + else + sb.append("?"); + } + sb.append(",lenient=").append(lenient); + sb.append(",firstDayOfWeek=").append(firstDayOfWeek); + sb.append(",minimalDaysInFirstWeek=").append(minimalDaysInFirstWeek); + sb.append("]"); + return sb.toString(); + } + + /** + * Saves the state of the object to the stream. Ideally we would + * only write the time field, but we need to be compatible with + * earlier versions. <br> + * + * This doesn't write the JDK1.1 field nextStamp to the stream, as + * I don't know what it is good for, and because the documentation + * says, that it could be omitted. */ + private void writeObject(ObjectOutputStream stream) throws IOException + { + if (! isTimeSet) + computeTime(); + stream.defaultWriteObject(); + } + + /** + * Reads the object back from stream (deserialization). + */ + private void readObject(ObjectInputStream stream) + throws IOException, ClassNotFoundException + { + stream.defaultReadObject(); + if (! isTimeSet) + computeTime(); + + if (serialVersionOnStream > 1) + { + // This is my interpretation of the serial number: + // Sun wants to remove all fields from the stream someday + // and will then increase the serialVersion number again. + // We prepare to be compatible. + fields = new int[FIELD_COUNT]; + isSet = new boolean[FIELD_COUNT]; + areFieldsSet = false; + } + } +} diff --git a/gcc-4.2.1/libjava/java/util/Currency.java b/gcc-4.2.1/libjava/java/util/Currency.java new file mode 100644 index 000000000..e1a28e0b8 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/Currency.java @@ -0,0 +1,355 @@ +/* Currency.java -- Representation of a currency + Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.text.NumberFormat; + +/** + * Representation of a currency for a particular locale. Each currency + * is identified by its ISO 4217 code, and only one instance of this + * class exists per currency. As a result, instances are created + * via the <code>getInstance()</code> methods rather than by using + * a constructor. + * + * @see java.util.Locale + * @author Guilhem Lavaux (guilhem.lavaux@free.fr) + * @author Dalibor Topic (robilad@kaffe.org) + * @author Bryce McKinlay (mckinlay@redhat.com) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.4 + */ +public final class Currency + implements Serializable +{ + /** + * For compatability with Sun's JDK + */ + static final long serialVersionUID = -158308464356906721L; + + /** + * The locale associated with this currency. + * + * @see #Currency(java.util.Locale) + * @see #getInstance(java.util.Locale) + * @see #getSymbol(java.util.Locale) + * @serial ignored. + */ + private transient Locale locale; + + /** + * The resource bundle which maps the currency to + * a ISO 4217 currency code. + * + * @see #getCurrencyCode() + * @serial ignored. + */ + private transient ResourceBundle res; + + /** + * The ISO 4217 currency code associated with this + * particular instance. + * + * @see #getCurrencyCode() + * @serial the ISO 4217 currency code + */ + private String currencyCode; + + /** + * A cache of <code>Currency</code> instances to + * ensure the singleton nature of this class. The key + * is the locale of the currency. + * + * @see #getInstance(java.util.Locale) + * @see #readResolve() + * @serial ignored. + */ + private static transient Map cache; + + /** + * Instantiates the cache. + */ + static + { + cache = new HashMap(); + } + + /** + * Default constructor for deserialization + */ + private Currency () + { + } + + /** + * Constructor to create a <code>Currency</code> object + * for a particular <code>Locale</code>. + * All components of the given locale, other than the + * country code, are ignored. The results of calling this + * method may vary over time, as the currency associated with + * a particular country changes. For countries without + * a given currency (e.g. Antarctica), the result is null. + * + * @param loc the locale for the new currency. + */ + private Currency (Locale loc) + { + this.locale = loc; + this.res = ResourceBundle.getBundle ("gnu.java.locale.LocaleInformation", + locale, ClassLoader.getSystemClassLoader()); + /* Retrieve the ISO4217 currency code */ + try + { + currencyCode = res.getString ("intlCurrencySymbol"); + } + catch (Exception _) + { + currencyCode = null; + } + } + + /** + * Returns the ISO4217 currency code of this currency. + * + * @return a <code>String</code> containing currency code. + */ + public String getCurrencyCode () + { + return currencyCode; + } + + /** + * Returns the number of digits which occur after the decimal point + * for this particular currency. For example, currencies such + * as the U.S. dollar, the Euro and the Great British pound have two + * digits following the decimal point to indicate the value which exists + * in the associated lower-valued coinage (cents in the case of the first + * two, pennies in the latter). Some currencies such as the Japanese + * Yen have no digits after the decimal point. In the case of pseudo + * currencies, such as IMF Special Drawing Rights, -1 is returned. + * + * @return the number of digits after the decimal separator for this currency. + */ + public int getDefaultFractionDigits () + { + NumberFormat currency = NumberFormat.getCurrencyInstance (locale); + + return currency.getMaximumFractionDigits(); + } + + /** + * Builds a new currency instance for this locale. + * All components of the given locale, other than the + * country code, are ignored. The results of calling this + * method may vary over time, as the currency associated with + * a particular country changes. For countries without + * a given currency (e.g. Antarctica), the result is null. + * + * @param locale a <code>Locale</code> instance. + * @return a new <code>Currency</code> instance. + * @throws NullPointerException if the locale or its + * country code is null. + * @throws IllegalArgumentException if the country of + * the given locale is not a supported ISO3166 code. + */ + public static Currency getInstance (Locale locale) + { + /** + * The new instance must be the only available instance + * for the currency it supports. We ensure this happens, + * while maintaining a suitable performance level, by + * creating the appropriate object on the first call to + * this method, and returning the cached instance on + * later calls. + */ + Currency newCurrency; + + /* Attempt to get the currency from the cache */ + newCurrency = (Currency) cache.get(locale); + if (newCurrency == null) + { + /* Create the currency for this locale */ + newCurrency = new Currency (locale); + /* Cache it */ + cache.put(locale, newCurrency); + } + /* Return the instance */ + return newCurrency; + } + + /** + * Builds the currency corresponding to the specified currency code. + * + * @param currencyCode a string representing a currency code. + * @return a new <code>Currency</code> instance. + * @throws NullPointerException if currencyCode is null. + * @throws IllegalArgumentException if the supplied currency code + * is not a supported ISO 4217 code. + */ + public static Currency getInstance (String currencyCode) + { + Locale[] allLocales = Locale.getAvailableLocales (); + + for (int i = 0;i < allLocales.length; i++) + { + Currency testCurrency = getInstance (allLocales[i]); + + if (testCurrency.getCurrencyCode() != null && + testCurrency.getCurrencyCode().equals(currencyCode)) + return testCurrency; + } + /* + * If we get this far, the code is not supported by any of + * our locales. + */ + throw new IllegalArgumentException("The currency code, " + currencyCode + + ", is not supported."); + } + + /** + * This method returns the symbol which precedes or follows a + * value in this particular currency. In cases where there is no + * such symbol for the currency, the ISO 4217 currency + * code is returned. + * + * @return the currency symbol, or the ISO 4217 currency code if + * one doesn't exist. + */ + public String getSymbol() + { + try + { + /* What does this return if there is no mapping? */ + return res.getString ("currencySymbol"); + } + catch (Exception _) + { + return null; + } + } + + /** + * <p> + * This method returns the symbol which precedes or follows a + * value in this particular currency. The returned value is + * the symbol used to denote the currency in the specified locale. + * </p> + * <p> + * For example, a supplied locale may specify a different symbol + * for the currency, due to conflicts with its own currency. + * This would be the case with the American currency, the dollar. + * Locales that also use a dollar-based currency (e.g. Canada, Australia) + * need to differentiate the American dollar using 'US$' rather than '$'. + * So, supplying one of these locales to <code>getSymbol()</code> would + * return this value, rather than the standard '$'. + * </p> + * <p> + * In cases where there is no such symbol for a particular currency, + * the ISO 4217 currency code is returned. + * </p> + * + * @param locale the locale to express the symbol in. + * @return the currency symbol, or the ISO 4217 currency code if + * one doesn't exist. + * @throws NullPointerException if the locale is null. + */ + public String getSymbol(Locale locale) + { + // TODO. The behaviour is unclear if locale != this.locale. + // First we need to implement fully LocaleInformation*.java + + /* + * FIXME: My reading of how this method works has this implementation + * as wrong. It should return a value relating to how the specified + * locale handles the symbol for this currency. This implementation + * seems to just do a variation of getInstance(locale). + */ + try + { + ResourceBundle localeResource = + ResourceBundle.getBundle ("gnu.java.locale.LocaleInformation", + locale, Currency.class.getClassLoader()); + + if (localeResource.equals(res)) + return localeResource.getString ("currencySymbol"); + else + return localeResource.getString ("intlCurrencySymbol"); + } + catch (Exception e1) + { + try + { + return res.getString ("intlCurrencySymbol"); + } + catch (Exception e2) + { + return null; + } + } + } + + /** + * Returns the international ISO4217 currency code of this currency. + * + * @return a <code>String</code> containing the ISO4217 currency code. + */ + public String toString() + { + return getCurrencyCode(); + } + + /** + * Resolves the deserialized object to the singleton instance for its + * particular currency. The currency code of the deserialized instance + * is used to return the correct instance. + * + * @return the singleton instance for the currency specified by the + * currency code of the deserialized object. This replaces + * the deserialized object as the returned object from + * deserialization. + * @throws ObjectStreamException if a problem occurs with deserializing + * the object. + */ + private Object readResolve() + throws ObjectStreamException + { + return getInstance(currencyCode); + } + +} diff --git a/gcc-4.2.1/libjava/java/util/GregorianCalendar.java b/gcc-4.2.1/libjava/java/util/GregorianCalendar.java new file mode 100644 index 000000000..dc77c2f50 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/GregorianCalendar.java @@ -0,0 +1,1358 @@ +/* java.util.GregorianCalendar + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + + +/** + * <p> + * This class represents the Gregorian calendar, that is used in most + * countries all over the world. It does also handle the Julian calendar + * for dates smaller than the date of the change to the Gregorian calendar. + * The Gregorian calendar differs from the Julian calendar by a different + * leap year rule (no leap year every 100 years, except if year is divisible + * by 400). + * </p> + * <p> + * This change date is different from country to country, and can be changed with + * <code>setGregorianChange</code>. The first countries to adopt the Gregorian + * calendar did so on the 15th of October, 1582. This date followed October + * the 4th, 1582 in the Julian calendar system. The non-existant days that were + * omitted when the change took place are interpreted as Gregorian dates. + * </p> + * <p> + * Prior to the changeover date, New Year's Day occurred on the 25th of March. + * However, this class always takes New Year's Day as being the 1st of January. + * Client code should manually adapt the year value, if required, for dates + * between January the 1st and March the 24th in years prior to the changeover. + * </p> + * <p> + * Any date infinitely forwards or backwards in time can be represented by + * this class. A <em>proleptic</em> calendar system is used, which allows + * future dates to be created via the existing rules. This allows meaningful + * and consistent dates to be produced for all years. However, dates are only + * historically accurate following March the 1st, 4AD when the Julian calendar + * system was adopted. Prior to this, leap year rules were applied erraticly. + * </p> + * <p> + * There are two eras available for the Gregorian calendar, namely BC and AD. + * </p> + * <p> + * Weeks are defined as a period of seven days, beginning on the first day + * of the week, as returned by <code>getFirstDayOfWeek()</code>, and ending + * on the day prior to this. + * </p> + * <p> + * The weeks of the year are numbered from 1 to a possible 53. The first week + * of the year is defined as the first week that contains at least the minimum + * number of days of the first week in the new year (retrieved via + * <code>getMinimalDaysInFirstWeek()</code>). All weeks after this are numbered + * from 2 onwards. + * </p> + * <p> + * For example, take the year 2004. It began on a Thursday. The first week + * of 2004 depends both on where a week begins and how long it must minimally + * last. Let's say that the week begins on a Monday and must have a minimum + * of 5 days. In this case, the first week begins on Monday, the 5th of January. + * The first 4 days (Thursday to Sunday) are not eligible, as they are too few + * to make up the minimum number of days of the first week which must be in + * the new year. If the minimum was lowered to 4 days, then the first week + * would instead begin on Monday, the 29th of December, 2003. This first week + * has 4 of its days in the new year, and is now eligible. + * </p> + * <p> + * The weeks of the month are numbered from 0 to a possible 6. The first week + * of the month (numbered 1) is a set of days, prior to the first day of the week, + * which number at least the minimum number of days in a week. Unlike the first + * week of the year, the first week of the month only uses days from that particular + * month. As a consequence, it may have a variable number of days (from the minimum + * number required up to a full week of 7) and it need not start on the first day of + * the week. It must, however, be following by the first day of the week, as this + * marks the beginning of week 2. Any days of the month which occur prior to the + * first week (because the first day of the week occurs before the minimum number + * of days is met) are seen as week 0. + * </p> + * <p> + * Again, we will take the example of the year 2004 to demonstrate this. September + * 2004 begins on a Wednesday. Taking our first day of the week as Monday, and the + * minimum length of the first week as 6, we find that week 1 runs from Monday, + * the 6th of September to Sunday the 12th. Prior to the 6th, there are only + * 5 days (Wednesday through to Sunday). This is too small a number to meet the + * minimum, so these are classed as being days in week 0. Week 2 begins on the + * 13th, and so on. This changes if we reduce the minimum to 5. In this case, + * week 1 is a truncated week from Wednesday the 1st to Sunday the 5th, and week + * 0 doesn't exist. The first seven day week is week 2, starting on the 6th. + * </p> + * <p> + * On using the <code>clear()</code> method, the Gregorian calendar returns + * to its default value of the 1st of January, 1970 AD 00:00:00 (the epoch). + * The day of the week is set to the correct day for that particular time. + * The day is also the first of the month, and the date is in week 0. + * </p> + * + * @see Calendar + * @see TimeZone + * @see Calendar#getFirstDayOfWeek() + * @see Calendar#getMinimalDaysInFirstWeek() + */ +public class GregorianCalendar extends Calendar +{ + /** + * Constant representing the era BC (Before Christ). + */ + public static final int BC = 0; + + /** + * Constant representing the era AD (Anno Domini). + */ + public static final int AD = 1; + + /** + * The point at which the Gregorian calendar rules were used. + * This is locale dependent; the default for most catholic + * countries is midnight (UTC) on October 5, 1582 (Julian), + * or October 15, 1582 (Gregorian). + * + * @serial the changeover point from the Julian calendar + * system to the Gregorian. + */ + private long gregorianCutover; + + /** + * For compatability with Sun's JDK. + */ + static final long serialVersionUID = -8125100834729963327L; + + /** + * The name of the resource bundle. Used only by getBundle() + */ + private static final String bundleName = "gnu.java.locale.Calendar"; + + /** + * Days in the epoch. Relative Jan 1, year '0' which is not a leap year. + * (although there is no year zero, this does not matter.) + * This is consistent with the formula: + * = (year-1)*365L + ((year-1) >> 2) + * + * Plus the gregorian correction: + * Math.floor((year-1) / 400.) - Math.floor((year-1) / 100.); + * For a correct julian date, the correction is -2 instead. + * + * The gregorian cutover in 1582 was 10 days, so by calculating the + * correction from year zero, we have 15 non-leap days (even centuries) + * minus 3 leap days (year 400,800,1200) = 12. Subtracting two corrects + * this to the correct number 10. + */ + private static final int EPOCH_DAYS = 719162; + + /** + * Constructs a new GregorianCalender representing the current + * time, using the default time zone and the default locale. + */ + public GregorianCalendar() + { + this(TimeZone.getDefault(), Locale.getDefault()); + } + + /** + * Constructs a new GregorianCalender representing the current + * time, using the specified time zone and the default locale. + * + * @param zone a time zone. + */ + public GregorianCalendar(TimeZone zone) + { + this(zone, Locale.getDefault()); + } + + /** + * Constructs a new GregorianCalender representing the current + * time, using the default time zone and the specified locale. + * + * @param locale a locale. + */ + public GregorianCalendar(Locale locale) + { + this(TimeZone.getDefault(), locale); + } + + /** + * Constructs a new GregorianCalender representing the current + * time with the given time zone and the given locale. + * + * @param zone a time zone. + * @param locale a locale. + */ + public GregorianCalendar(TimeZone zone, Locale locale) + { + this(zone, locale, false); + setTimeInMillis(System.currentTimeMillis()); + complete(); + } + + /** + * Common constructor that all constructors should call. + * @param zone a time zone. + * @param locale a locale. + * @param unused unused parameter to make the signature differ from + * the public constructor (TimeZone, Locale). + */ + private GregorianCalendar(TimeZone zone, Locale locale, boolean unused) + { + super(zone, locale); + ResourceBundle rb = ResourceBundle.getBundle(bundleName, locale, + ClassLoader + .getSystemClassLoader()); + gregorianCutover = ((Date) rb.getObject("gregorianCutOver")).getTime(); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + */ + public GregorianCalendar(int year, int month, int day) + { + this(TimeZone.getDefault(), Locale.getDefault(), false); + set(year, month, day); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + * @param hour corresponds to the HOUR_OF_DAY time field. + * @param minute corresponds to the MINUTE time field. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute) + { + this(TimeZone.getDefault(), Locale.getDefault(), false); + set(year, month, day, hour, minute); + } + + /** + * Constructs a new GregorianCalendar representing midnight on the + * given date with the default time zone and locale. + * + * @param year corresponds to the YEAR time field. + * @param month corresponds to the MONTH time field. + * @param day corresponds to the DAY time field. + * @param hour corresponds to the HOUR_OF_DAY time field. + * @param minute corresponds to the MINUTE time field. + * @param second corresponds to the SECOND time field. + */ + public GregorianCalendar(int year, int month, int day, int hour, int minute, + int second) + { + this(TimeZone.getDefault(), Locale.getDefault(), false); + set(year, month, day, hour, minute, second); + } + + /** + * Sets the date of the switch from Julian dates to Gregorian dates. + * You can use <code>new Date(Long.MAX_VALUE)</code> to use a pure + * Julian calendar, or <code>Long.MIN_VALUE</code> for a pure Gregorian + * calendar. + * + * @param date the date of the change. + */ + public void setGregorianChange(Date date) + { + gregorianCutover = date.getTime(); + } + + /** + * Gets the date of the switch from Julian dates to Gregorian dates. + * + * @return the date of the change. + */ + public final Date getGregorianChange() + { + return new Date(gregorianCutover); + } + + /** + * <p> + * Determines if the given year is a leap year. The result is + * undefined if the Gregorian change took place in 1800, so that + * the end of February is skipped, and that year is specified. + * (well...). + * </p> + * <p> + * To specify a year in the BC era, use a negative value calculated + * as 1 - y, where y is the required year in BC. So, 1 BC is 0, + * 2 BC is -1, 3 BC is -2, etc. + * </p> + * + * @param year a year (use a negative value for BC). + * @return true, if the given year is a leap year, false otherwise. + */ + public boolean isLeapYear(int year) + { + // Only years divisible by 4 can be leap years + if ((year & 3) != 0) + return false; + + // Is the leap-day a Julian date? Then it's a leap year + if (! isGregorian(year, 31 + 29 - 1)) + return true; + + // Apply gregorian rules otherwise + return ((year % 100) != 0 || (year % 400) == 0); + } + + /** + * Retrieves the day of the week corresponding to the specified + * day of the specified year. + * + * @param year the year in which the dayOfYear occurs. + * @param dayOfYear the day of the year (an integer between 0 and + * and 366) + */ + private int getWeekDay(int year, int dayOfYear) + { + boolean greg = isGregorian(year, dayOfYear); + int day = (int) getLinearDay(year, dayOfYear, greg); + + // The epoch was a thursday. + int weekday = (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + return weekday; + } + + /** + * Returns the day of the week for the first day of a given month (0..11) + */ + private int getFirstDayOfMonth(int year, int month) + { + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + if (month > 11) + { + year += (month / 12); + month = month % 12; + } + + if (month < 0) + { + year += (int) month / 12; + month = month % 12; + if (month < 0) + { + month += 12; + year--; + } + } + + int dayOfYear = dayCount[month] + 1; + if (month > 1) + if (isLeapYear(year)) + dayOfYear++; + + boolean greg = isGregorian(year, dayOfYear); + int day = (int) getLinearDay(year, dayOfYear, greg); + + // The epoch was a thursday. + int weekday = (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + return weekday; + } + + /** + * Takes a year, and a (zero based) day of year and determines + * if it is gregorian or not. + */ + private boolean isGregorian(int year, int dayOfYear) + { + int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear + - EPOCH_DAYS; // gregorian days from 1 to epoch. + int gregFactor = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + return ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover); + } + + /** + * Check set fields for validity, without leniency. + * + * @throws IllegalArgumentException if a field is invalid + */ + private void nonLeniencyCheck() throws IllegalArgumentException + { + int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int year = fields[YEAR]; + int month = fields[MONTH]; + int leap = isLeapYear(year) ? 1 : 0; + + if (isSet[ERA] && fields[ERA] != AD && fields[ERA] != BC) + throw new IllegalArgumentException("Illegal ERA."); + if (isSet[YEAR] && fields[YEAR] < 1) + throw new IllegalArgumentException("Illegal YEAR."); + if (isSet[MONTH] && (month < 0 || month > 11)) + throw new IllegalArgumentException("Illegal MONTH."); + if (isSet[WEEK_OF_YEAR]) + { + int daysInYear = 365 + leap; + daysInYear += (getFirstDayOfMonth(year, 0) - 1); // pad first week + int last = getFirstDayOfMonth(year, 11) + 4; + if (last > 7) + last -= 7; + daysInYear += 7 - last; + int weeks = daysInYear / 7; + if (fields[WEEK_OF_YEAR] < 1 || fields[WEEK_OF_YEAR] > weeks) + throw new IllegalArgumentException("Illegal WEEK_OF_YEAR."); + } + + if (isSet[WEEK_OF_MONTH]) + { + int weeks = (month == 1 && leap == 0) ? 4 : 5; + if (fields[WEEK_OF_MONTH] < 1 || fields[WEEK_OF_MONTH] > weeks) + throw new IllegalArgumentException("Illegal WEEK_OF_MONTH."); + } + + if (isSet[DAY_OF_MONTH]) + if (fields[DAY_OF_MONTH] < 1 + || fields[DAY_OF_MONTH] > month_days[month] + + ((month == 1) ? leap : 0)) + throw new IllegalArgumentException("Illegal DAY_OF_MONTH."); + + if (isSet[DAY_OF_YEAR] + && (fields[DAY_OF_YEAR] < 1 || fields[DAY_OF_YEAR] > 365 + leap)) + throw new IllegalArgumentException("Illegal DAY_OF_YEAR."); + + if (isSet[DAY_OF_WEEK] + && (fields[DAY_OF_WEEK] < 1 || fields[DAY_OF_WEEK] > 7)) + throw new IllegalArgumentException("Illegal DAY_OF_WEEK."); + + if (isSet[DAY_OF_WEEK_IN_MONTH]) + { + int weeks = (month == 1 && leap == 0) ? 4 : 5; + if (fields[DAY_OF_WEEK_IN_MONTH] < -weeks + || fields[DAY_OF_WEEK_IN_MONTH] > weeks) + throw new IllegalArgumentException("Illegal DAY_OF_WEEK_IN_MONTH."); + } + + if (isSet[AM_PM] && fields[AM_PM] != AM && fields[AM_PM] != PM) + throw new IllegalArgumentException("Illegal AM_PM."); + if (isSet[HOUR] && (fields[HOUR] < 0 || fields[HOUR] > 11)) + throw new IllegalArgumentException("Illegal HOUR."); + if (isSet[HOUR_OF_DAY] + && (fields[HOUR_OF_DAY] < 0 || fields[HOUR_OF_DAY] > 23)) + throw new IllegalArgumentException("Illegal HOUR_OF_DAY."); + if (isSet[MINUTE] && (fields[MINUTE] < 0 || fields[MINUTE] > 59)) + throw new IllegalArgumentException("Illegal MINUTE."); + if (isSet[SECOND] && (fields[SECOND] < 0 || fields[SECOND] > 59)) + throw new IllegalArgumentException("Illegal SECOND."); + if (isSet[MILLISECOND] + && (fields[MILLISECOND] < 0 || fields[MILLISECOND] > 999)) + throw new IllegalArgumentException("Illegal MILLISECOND."); + if (isSet[ZONE_OFFSET] + && (fields[ZONE_OFFSET] < -12 * 60 * 60 * 1000L + || fields[ZONE_OFFSET] > 12 * 60 * 60 * 1000L)) + throw new IllegalArgumentException("Illegal ZONE_OFFSET."); + if (isSet[DST_OFFSET] + && (fields[DST_OFFSET] < -12 * 60 * 60 * 1000L + || fields[DST_OFFSET] > 12 * 60 * 60 * 1000L)) + throw new IllegalArgumentException("Illegal DST_OFFSET."); + } + + /** + * Converts the time field values (<code>fields</code>) to + * milliseconds since the epoch UTC (<code>time</code>). + * + * @throws IllegalArgumentException if any calendar fields + * are invalid. + */ + protected synchronized void computeTime() + { + int millisInDay = 0; + int era = fields[ERA]; + int year = fields[YEAR]; + int month = fields[MONTH]; + int day = fields[DAY_OF_MONTH]; + + int minute = fields[MINUTE]; + int second = fields[SECOND]; + int millis = fields[MILLISECOND]; + int[] month_days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + int[] dayCount = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + int hour = 0; + + if (! isLenient()) + nonLeniencyCheck(); + + if (! isSet[MONTH] && (! isSet[DAY_OF_WEEK] || isSet[WEEK_OF_YEAR])) + { + // 5: YEAR + DAY_OF_WEEK + WEEK_OF_YEAR + if (isSet[WEEK_OF_YEAR]) + { + int first = getFirstDayOfMonth(year, 0); + int offs = 1; + int daysInFirstWeek = getFirstDayOfWeek() - first; + if (daysInFirstWeek <= 0) + daysInFirstWeek += 7; + + if (daysInFirstWeek < getMinimalDaysInFirstWeek()) + offs += daysInFirstWeek; + else + offs -= 7 - daysInFirstWeek; + month = 0; + day = offs + 7 * (fields[WEEK_OF_YEAR] - 1); + offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek(); + + if (offs < 0) + offs += 7; + day += offs; + } + else + { + // 4: YEAR + DAY_OF_YEAR + month = 0; + day = fields[DAY_OF_YEAR]; + } + } + else + { + if (isSet[DAY_OF_WEEK]) + { + int first = getFirstDayOfMonth(year, month); + + // 3: YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK + if (isSet[DAY_OF_WEEK_IN_MONTH]) + { + if (fields[DAY_OF_WEEK_IN_MONTH] < 0) + { + month++; + first = getFirstDayOfMonth(year, month); + day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH]); + } + else + day = 1 + 7 * (fields[DAY_OF_WEEK_IN_MONTH] - 1); + + int offs = fields[DAY_OF_WEEK] - first; + if (offs < 0) + offs += 7; + day += offs; + } + else + { // 2: YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK + int offs = 1; + int daysInFirstWeek = getFirstDayOfWeek() - first; + if (daysInFirstWeek <= 0) + daysInFirstWeek += 7; + + if (daysInFirstWeek < getMinimalDaysInFirstWeek()) + offs += daysInFirstWeek; + else + offs -= 7 - daysInFirstWeek; + + day = offs + 7 * (fields[WEEK_OF_MONTH] - 1); + offs = fields[DAY_OF_WEEK] - getFirstDayOfWeek(); + if (offs <= 0) + offs += 7; + day += offs; + } + } + + // 1: YEAR + MONTH + DAY_OF_MONTH + } + if (era == BC && year > 0) + year = 1 - year; + + // rest of code assumes day/month/year set + // should negative BC years be AD? + // get the hour (but no check for validity) + if (isSet[HOUR]) + { + hour = fields[HOUR]; + if (fields[AM_PM] == PM) + hour += 12; + } + else + hour = fields[HOUR_OF_DAY]; + + // Read the era,year,month,day fields and convert as appropriate. + // Calculate number of milliseconds into the day + // This takes care of both h, m, s, ms over/underflows. + long allMillis = (((hour * 60L) + minute) * 60L + second) * 1000L + millis; + day += allMillis / (24 * 60 * 60 * 1000L); + millisInDay = (int) (allMillis % (24 * 60 * 60 * 1000L)); + + if (month < 0) + { + year += (int) month / 12; + month = month % 12; + if (month < 0) + { + month += 12; + year--; + } + } + if (month > 11) + { + year += (month / 12); + month = month % 12; + } + + month_days[1] = isLeapYear(year) ? 29 : 28; + + while (day <= 0) + { + if (month == 0) + { + year--; + month_days[1] = isLeapYear(year) ? 29 : 28; + } + month = (month + 11) % 12; + day += month_days[month]; + } + while (day > month_days[month]) + { + day -= (month_days[month]); + month = (month + 1) % 12; + if (month == 0) + { + year++; + month_days[1] = isLeapYear(year) ? 29 : 28; + } + } + + // ok, by here we have valid day,month,year,era and millisinday + int dayOfYear = dayCount[month] + day - 1; // (day starts on 1) + if (isLeapYear(year) && month > 1) + dayOfYear++; + + int relativeDay = (year - 1) * 365 + ((year - 1) >> 2) + dayOfYear + - EPOCH_DAYS; // gregorian days from 1 to epoch. + int gregFactor = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + if ((relativeDay + gregFactor) * 60L * 60L * 24L * 1000L >= gregorianCutover) + relativeDay += gregFactor; + else + relativeDay -= 2; + + time = relativeDay * (24 * 60 * 60 * 1000L) + millisInDay; + + // the epoch was a Thursday. + int weekday = (int) (relativeDay + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + fields[DAY_OF_WEEK] = weekday; + + // Time zone corrections. + TimeZone zone = getTimeZone(); + int rawOffset = isSet[ZONE_OFFSET] ? fields[ZONE_OFFSET] + : zone.getRawOffset(); + + int dstOffset = isSet[DST_OFFSET] ? fields[DST_OFFSET] + : (zone.getOffset((year < 0) ? BC : AD, + (year < 0) ? 1 - year + : year, + month, day, weekday, + millisInDay) + - zone.getRawOffset()); + + time -= rawOffset + dstOffset; + + isTimeSet = true; + } + + /** + * Get the linear day in days since the epoch, using the + * Julian or Gregorian calendar as specified. If you specify a + * nonpositive year it is interpreted as BC as following: 0 is 1 + * BC, -1 is 2 BC and so on. + * + * @param year the year of the date. + * @param dayOfYear the day of year of the date; 1 based. + * @param gregorian <code>true</code>, if we should use the Gregorian rules. + * @return the days since the epoch, may be negative. + */ + private long getLinearDay(int year, int dayOfYear, boolean gregorian) + { + // The 13 is the number of days, that were omitted in the Gregorian + // Calender until the epoch. + // We shift right by 2 instead of dividing by 4, to get correct + // results for negative years (and this is even more efficient). + long julianDay = (year - 1) * 365L + ((year - 1) >> 2) + (dayOfYear - 1) + - EPOCH_DAYS; // gregorian days from 1 to epoch. + + if (gregorian) + { + // subtract the days that are missing in gregorian calendar + // with respect to julian calendar. + // + // Okay, here we rely on the fact that the gregorian + // calendar was introduced in the AD era. This doesn't work + // with negative years. + // + // The additional leap year factor accounts for the fact that + // a leap day is not seen on Jan 1 of the leap year. + int gregOffset = (int) Math.floor((double) (year - 1) / 400.) + - (int) Math.floor((double) (year - 1) / 100.); + + return julianDay + gregOffset; + } + else + julianDay -= 2; + return julianDay; + } + + /** + * Converts the given linear day into era, year, month, + * day_of_year, day_of_month, day_of_week, and writes the result + * into the fields array. + * + * @param day the linear day. + * @param gregorian true, if we should use Gregorian rules. + */ + private void calculateDay(int[] fields, long day, boolean gregorian) + { + // the epoch was a Thursday. + int weekday = (int) (day + THURSDAY) % 7; + if (weekday <= 0) + weekday += 7; + fields[DAY_OF_WEEK] = weekday; + + // get a first approximation of the year. This may be one + // year too big. + int year = 1970 + + (int) (gregorian + ? ((day - 100L) * 400L) / (365L * 400L + 100L - 4L + + 1L) : ((day - 100L) * 4L) / (365L * 4L + 1L)); + if (day >= 0) + year++; + + long firstDayOfYear = getLinearDay(year, 1, gregorian); + + // Now look in which year day really lies. + if (day < firstDayOfYear) + { + year--; + firstDayOfYear = getLinearDay(year, 1, gregorian); + } + + day -= firstDayOfYear - 1; // day of year, one based. + + fields[DAY_OF_YEAR] = (int) day; + if (year <= 0) + { + fields[ERA] = BC; + fields[YEAR] = 1 - year; + } + else + { + fields[ERA] = AD; + fields[YEAR] = year; + } + + int leapday = isLeapYear(year) ? 1 : 0; + if (day <= 31 + 28 + leapday) + { + fields[MONTH] = (int) day / 32; // 31->JANUARY, 32->FEBRUARY + fields[DAY_OF_MONTH] = (int) day - 31 * fields[MONTH]; + } + else + { + // A few more magic formulas + int scaledDay = ((int) day - leapday) * 5 + 8; + fields[MONTH] = scaledDay / (31 + 30 + 31 + 30 + 31); + fields[DAY_OF_MONTH] = (scaledDay % (31 + 30 + 31 + 30 + 31)) / 5 + 1; + } + } + + /** + * Converts the milliseconds since the epoch UTC + * (<code>time</code>) to time fields + * (<code>fields</code>). + */ + protected synchronized void computeFields() + { + boolean gregorian = (time >= gregorianCutover); + + TimeZone zone = getTimeZone(); + fields[ZONE_OFFSET] = zone.getRawOffset(); + long localTime = time + fields[ZONE_OFFSET]; + + long day = localTime / (24 * 60 * 60 * 1000L); + int millisInDay = (int) (localTime % (24 * 60 * 60 * 1000L)); + + if (millisInDay < 0) + { + millisInDay += (24 * 60 * 60 * 1000); + day--; + } + + calculateDay(fields, day, gregorian); + fields[DST_OFFSET] = zone.getOffset(fields[ERA], fields[YEAR], + fields[MONTH], fields[DAY_OF_MONTH], + fields[DAY_OF_WEEK], millisInDay) + - fields[ZONE_OFFSET]; + + millisInDay += fields[DST_OFFSET]; + if (millisInDay >= 24 * 60 * 60 * 1000) + { + millisInDay -= 24 * 60 * 60 * 1000; + calculateDay(fields, ++day, gregorian); + } + + fields[DAY_OF_WEEK_IN_MONTH] = (fields[DAY_OF_MONTH] + 6) / 7; + + // which day of the week are we (0..6), relative to getFirstDayOfWeek + int relativeWeekday = (7 + fields[DAY_OF_WEEK] - getFirstDayOfWeek()) % 7; + + fields[WEEK_OF_MONTH] = (fields[DAY_OF_MONTH] - relativeWeekday + 12) / 7; + + int weekOfYear = (fields[DAY_OF_YEAR] - relativeWeekday + 6) / 7; + + // Do the Correction: getMinimalDaysInFirstWeek() is always in the + // first week. + int minDays = getMinimalDaysInFirstWeek(); + int firstWeekday = (7 + getWeekDay(fields[YEAR], minDays) + - getFirstDayOfWeek()) % 7; + if (minDays - firstWeekday < 1) + weekOfYear++; + fields[WEEK_OF_YEAR] = weekOfYear; + + int hourOfDay = millisInDay / (60 * 60 * 1000); + fields[AM_PM] = (hourOfDay < 12) ? AM : PM; + int hour = hourOfDay % 12; + fields[HOUR] = hour; + fields[HOUR_OF_DAY] = hourOfDay; + millisInDay %= (60 * 60 * 1000); + fields[MINUTE] = millisInDay / (60 * 1000); + millisInDay %= (60 * 1000); + fields[SECOND] = millisInDay / (1000); + fields[MILLISECOND] = millisInDay % 1000; + + areFieldsSet = isSet[ERA] = isSet[YEAR] = isSet[MONTH] = isSet[WEEK_OF_YEAR] = isSet[WEEK_OF_MONTH] = isSet[DAY_OF_MONTH] = isSet[DAY_OF_YEAR] = isSet[DAY_OF_WEEK] = isSet[DAY_OF_WEEK_IN_MONTH] = isSet[AM_PM] = isSet[HOUR] = isSet[HOUR_OF_DAY] = isSet[MINUTE] = isSet[SECOND] = isSet[MILLISECOND] = isSet[ZONE_OFFSET] = isSet[DST_OFFSET] = true; + } + + /** + * Return a hash code for this object, following the general contract + * specified by {@link Object#hashCode()}. + * @return the hash code + */ + public int hashCode() + { + int val = (int) ((gregorianCutover >>> 32) ^ (gregorianCutover & 0xffffffff)); + return super.hashCode() ^ val; + } + + /** + * Compares the given calendar with this. An object, o, is + * equivalent to this if it is also a <code>GregorianCalendar</code> + * with the same time since the epoch under the same conditions + * (same change date and same time zone). + * + * @param o the object to that we should compare. + * @return true, if the given object is a calendar, that represents + * the same time (but doesn't necessarily have the same fields). + * @throws IllegalArgumentException if one of the fields + * <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public boolean equals(Object o) + { + if (! (o instanceof GregorianCalendar)) + return false; + + GregorianCalendar cal = (GregorianCalendar) o; + return (cal.gregorianCutover == gregorianCutover + && super.equals(o)); + } + + /** + * Adds the specified amount of time to the given time field. The + * amount may be negative to subtract the time. If the field overflows + * it does what you expect: Jan, 25 + 10 Days is Feb, 4. + * @param field one of the time field constants. + * @param amount the amount of time to add. + * @exception IllegalArgumentException if <code>field</code> is + * <code>ZONE_OFFSET</code>, <code>DST_OFFSET</code>, or invalid; or + * if <code>amount</code> contains an out-of-range value and the calendar + * is not in lenient mode. + */ + public void add(int field, int amount) + { + switch (field) + { + case YEAR: + complete(); + fields[YEAR] += amount; + isTimeSet = false; + break; + case MONTH: + complete(); + int months = fields[MONTH] + amount; + fields[YEAR] += months / 12; + fields[MONTH] = months % 12; + if (fields[MONTH] < 0) + { + fields[MONTH] += 12; + fields[YEAR]--; + } + int maxDay = getActualMaximum(DAY_OF_MONTH); + if (fields[DAY_OF_MONTH] > maxDay) + fields[DAY_OF_MONTH] = maxDay; + set(YEAR, fields[YEAR]); + set(MONTH, fields[MONTH]); + break; + case DAY_OF_MONTH: + case DAY_OF_YEAR: + case DAY_OF_WEEK: + if (! isTimeSet) + computeTime(); + time += amount * (24 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case WEEK_OF_YEAR: + case WEEK_OF_MONTH: + case DAY_OF_WEEK_IN_MONTH: + if (! isTimeSet) + computeTime(); + time += amount * (7 * 24 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case AM_PM: + if (! isTimeSet) + computeTime(); + time += amount * (12 * 60 * 60 * 1000L); + areFieldsSet = false; + break; + case HOUR: + case HOUR_OF_DAY: + if (! isTimeSet) + computeTime(); + time += amount * (60 * 60 * 1000L); + areFieldsSet = false; + break; + case MINUTE: + if (! isTimeSet) + computeTime(); + time += amount * (60 * 1000L); + areFieldsSet = false; + break; + case SECOND: + if (! isTimeSet) + computeTime(); + time += amount * (1000L); + areFieldsSet = false; + break; + case MILLISECOND: + if (! isTimeSet) + computeTime(); + time += amount; + areFieldsSet = false; + break; + case ZONE_OFFSET: + case DST_OFFSET:default: + throw new IllegalArgumentException("Invalid or unknown field"); + } + } + + /** + * Rolls the specified time field up or down. This means add one + * to the specified field, but don't change the other fields. If + * the maximum for this field is reached, start over with the + * minimum value. + * + * <strong>Note:</strong> There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically converted to July, 1. + * This requires lenient settings. + * + * @param field the time field. One of the time field constants. + * @param up the direction, true for up, false for down. + * @throws IllegalArgumentException if one of the fields + * <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public void roll(int field, boolean up) + { + roll(field, up ? 1 : -1); + } + + /** + * Checks that the fields are still within their legal bounds, + * following use of the <code>roll()</code> method. + * + * @param field the field to check. + * @param delta multipler for alterations to the <code>time</code>. + * @see #roll(int, boolean) + * @see #roll(int, int) + */ + private void cleanUpAfterRoll(int field, int delta) + { + switch (field) + { + case ERA: + case YEAR: + case MONTH: + // check that day of month is still in correct range + if (fields[DAY_OF_MONTH] > getActualMaximum(DAY_OF_MONTH)) + fields[DAY_OF_MONTH] = getActualMaximum(DAY_OF_MONTH); + isTimeSet = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + break; + case DAY_OF_MONTH: + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (24 * 60 * 60 * 1000L); + break; + case WEEK_OF_MONTH: + isSet[DAY_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case DAY_OF_WEEK_IN_MONTH: + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case DAY_OF_YEAR: + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_WEEK] = false; + isSet[WEEK_OF_YEAR] = false; + time += delta * (24 * 60 * 60 * 1000L); + break; + case WEEK_OF_YEAR: + isSet[MONTH] = false; + isSet[DAY_OF_MONTH] = false; + isSet[WEEK_OF_MONTH] = false; + isSet[DAY_OF_WEEK_IN_MONTH] = false; + isSet[DAY_OF_YEAR] = false; + time += delta * (7 * 24 * 60 * 60 * 1000L); + break; + case AM_PM: + isSet[HOUR_OF_DAY] = false; + time += delta * (12 * 60 * 60 * 1000L); + break; + case HOUR: + isSet[HOUR_OF_DAY] = false; + time += delta * (60 * 60 * 1000L); + break; + case HOUR_OF_DAY: + isSet[HOUR] = false; + isSet[AM_PM] = false; + time += delta * (60 * 60 * 1000L); + break; + case MINUTE: + time += delta * (60 * 1000L); + break; + case SECOND: + time += delta * (1000L); + break; + case MILLISECOND: + time += delta; + break; + } + } + + /** + * Rolls the specified time field by the given amount. This means + * add amount to the specified field, but don't change the other + * fields. If the maximum for this field is reached, start over + * with the minimum value and vice versa for negative amounts. + * + * <strong>Note:</strong> There may be situation, where the other + * fields must be changed, e.g rolling the month on May, 31. + * The date June, 31 is automatically corrected to June, 30. + * + * @param field the time field. One of the time field constants. + * @param amount the amount by which we should roll. + * @throws IllegalArgumentException if one of the fields + * <code>ZONE_OFFSET</code> or <code>DST_OFFSET</code> is + * specified, if an unknown field is specified or if one + * of the calendar fields receives an illegal value when + * leniancy is not enabled. + */ + public void roll(int field, int amount) + { + switch (field) + { + case DAY_OF_WEEK: + // day of week is special: it rolls automatically + add(field, amount); + return; + case ZONE_OFFSET: + case DST_OFFSET: + throw new IllegalArgumentException("Can't roll time zone"); + } + complete(); + int min = getActualMinimum(field); + int range = getActualMaximum(field) - min + 1; + int oldval = fields[field]; + int newval = (oldval - min + range + amount) % range + min; + if (newval < min) + newval += range; + fields[field] = newval; + cleanUpAfterRoll(field, newval - oldval); + } + + /** + * The minimum values for the calendar fields. + */ + private static final int[] minimums = + { + BC, 1, 0, 0, 1, 1, 1, SUNDAY, 1, AM, + 1, 0, 0, 0, 0, -(12 * 60 * 60 * 1000), + 0 + }; + + /** + * The maximum values for the calendar fields. + */ + private static final int[] maximums = + { + AD, 5000000, 11, 53, 5, 31, 366, + SATURDAY, 5, PM, 12, 23, 59, 59, 999, + +(12 * 60 * 60 * 1000), + (12 * 60 * 60 * 1000) + }; + + /** + * Gets the smallest value that is allowed for the specified field. + * + * @param field one of the time field constants. + * @return the smallest value for the specified field. + */ + public int getMinimum(int field) + { + return minimums[field]; + } + + /** + * Gets the biggest value that is allowed for the specified field. + * + * @param field one of the time field constants. + * @return the biggest value. + */ + public int getMaximum(int field) + { + return maximums[field]; + } + + /** + * Gets the greatest minimum value that is allowed for the specified field. + * This is the largest value returned by the <code>getActualMinimum(int)</code> + * method. + * + * @param field the time field. One of the time field constants. + * @return the greatest minimum value. + * @see #getActualMinimum(int) + */ + public int getGreatestMinimum(int field) + { + if (field == WEEK_OF_YEAR) + return 1; + return minimums[field]; + } + + /** + * Gets the smallest maximum value that is allowed for the + * specified field. This is the smallest value returned + * by the <code>getActualMaximum(int)</code>. For example, + * this is 28 for DAY_OF_MONTH (as all months have at least + * 28 days). + * + * @param field the time field. One of the time field constants. + * @return the least maximum value. + * @see #getActualMaximum(int) + * @since 1.2 + */ + public int getLeastMaximum(int field) + { + switch (field) + { + case WEEK_OF_YEAR: + return 52; + case DAY_OF_MONTH: + return 28; + case DAY_OF_YEAR: + return 365; + case DAY_OF_WEEK_IN_MONTH: + case WEEK_OF_MONTH: + return 4; + default: + return maximums[field]; + } + } + + /** + * Gets the actual minimum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. Note that + * this calls <code>complete()</code> if not enough fields are set. This + * can have ugly side effects. The value given depends on the current + * time used by this instance. + * + * @param field the time field. One of the time field constants. + * @return the actual minimum value. + * @since 1.2 + */ + public int getActualMinimum(int field) + { + if (field == WEEK_OF_YEAR) + { + int min = getMinimalDaysInFirstWeek(); + if (min == 0) + return 1; + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + int weekday = getWeekDay(year, min); + if ((7 + weekday - getFirstDayOfWeek()) % 7 >= min - 1) + return 1; + return 0; + } + return minimums[field]; + } + + /** + * Gets the actual maximum value that is allowed for the specified field. + * This value is dependent on the values of the other fields. Note that + * this calls <code>complete()</code> if not enough fields are set. This + * can have ugly side effects. The value given depends on the current time + * used by this instance; thus, leap years have a maximum day of month value of + * 29, rather than 28. + * + * @param field the time field. One of the time field constants. + * @return the actual maximum value. + */ + public int getActualMaximum(int field) + { + switch (field) + { + case WEEK_OF_YEAR: + { + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + + // This is wrong for the year that contains the gregorian change. + // I.e it gives the weeks in the julian year or in the gregorian + // year in that case. + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + int lastDay = isLeapYear(year) ? 366 : 365; + int weekday = getWeekDay(year, lastDay); + int week = (lastDay + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7; + + int minimalDays = getMinimalDaysInFirstWeek(); + int firstWeekday = getWeekDay(year, minimalDays); + /* + * Is there a set of days at the beginning of the year, before the + * first day of the week, equal to or greater than the minimum number + * of days required in the first week? + */ + if (minimalDays - (7 + firstWeekday - getFirstDayOfWeek()) % 7 < 1) + return week + 1; /* Add week 1: firstWeekday through to firstDayOfWeek */ + } + case DAY_OF_MONTH: + { + if (! areFieldsSet || ! isSet[MONTH]) + complete(); + int month = fields[MONTH]; + + // If you change this, you should also change + // SimpleTimeZone.getDaysInMonth(); + if (month == FEBRUARY) + { + if (! isSet[YEAR] || ! isSet[ERA]) + complete(); + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + return isLeapYear(year) ? 29 : 28; + } + else if (month < AUGUST) + return 31 - (month & 1); + else + return 30 + (month & 1); + } + case DAY_OF_YEAR: + { + if (! areFieldsSet || ! isSet[ERA] || ! isSet[YEAR]) + complete(); + int year = fields[ERA] == AD ? fields[YEAR] : 1 - fields[YEAR]; + return isLeapYear(year) ? 366 : 365; + } + case DAY_OF_WEEK_IN_MONTH: + { + // This is wrong for the month that contains the gregorian change. + int daysInMonth = getActualMaximum(DAY_OF_MONTH); + + // That's black magic, I know + return (daysInMonth - (fields[DAY_OF_MONTH] - 1) % 7 + 6) / 7; + } + case WEEK_OF_MONTH: + { + int daysInMonth = getActualMaximum(DAY_OF_MONTH); + int weekday = (daysInMonth - fields[DAY_OF_MONTH] + + fields[DAY_OF_WEEK] - SUNDAY) % 7 + SUNDAY; + return (daysInMonth + 6 - (7 + weekday - getFirstDayOfWeek()) % 7) / 7; + } + default: + return maximums[field]; + } + } +} diff --git a/gcc-4.2.1/libjava/java/util/Locale.java b/gcc-4.2.1/libjava/java/util/Locale.java new file mode 100644 index 000000000..03689aa7a --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/Locale.java @@ -0,0 +1,864 @@ +/* Locale.java -- i18n locales + Copyright (C) 1998, 1999, 2001, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import gnu.classpath.SystemProperties; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +/** + * Locales represent a specific country and culture. Classes which can be + * passed a Locale object tailor their information for a given locale. For + * instance, currency number formatting is handled differently for the USA + * and France. + * + * <p>Locales are made up of a language code, a country code, and an optional + * set of variant strings. Language codes are represented by + * <a href="http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt"> + * ISO 639:1988</a> w/ additions from ISO 639/RA Newsletter No. 1/1989 + * and a decision of the Advisory Committee of ISO/TC39 on August 8, 1997. + * + * <p>Country codes are represented by + * <a href="http://www.chemie.fu-berlin.de/diverse/doc/ISO_3166.html"> + * ISO 3166</a>. Variant strings are vendor and browser specific. Standard + * variant strings include "POSIX" for POSIX, "WIN" for MS-Windows, and + * "MAC" for Macintosh. When there is more than one variant string, they must + * be separated by an underscore (U+005F). + * + * <p>The default locale is determined by the values of the system properties + * user.language, user.region, and user.variant, defaulting to "en". Note that + * the locale does NOT contain the conversion and formatting capabilities (for + * that, use ResourceBundle and java.text). Rather, it is an immutable tag + * object for identifying a given locale, which is referenced by these other + * classes when they must make locale-dependent decisions. + * + * @see ResourceBundle + * @see java.text.Format + * @see java.text.NumberFormat + * @see java.text.Collator + * @author Jochen Hoenicke + * @author Paul Fisher + * @author Eric Blake (ebb9@email.byu.edu) + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.1 + * @status updated to 1.4 + */ +public final class Locale implements Serializable, Cloneable +{ + /** Locale which represents the English language. */ + public static final Locale ENGLISH = getLocale("en"); + + /** Locale which represents the French language. */ + public static final Locale FRENCH = getLocale("fr"); + + /** Locale which represents the German language. */ + public static final Locale GERMAN = getLocale("de"); + + /** Locale which represents the Italian language. */ + public static final Locale ITALIAN = getLocale("it"); + + /** Locale which represents the Japanese language. */ + public static final Locale JAPANESE = getLocale("ja"); + + /** Locale which represents the Korean language. */ + public static final Locale KOREAN = getLocale("ko"); + + /** Locale which represents the Chinese language. */ + public static final Locale CHINESE = getLocale("zh"); + + /** Locale which represents the Chinese language as used in China. */ + public static final Locale SIMPLIFIED_CHINESE = getLocale("zh", "CN"); + + /** + * Locale which represents the Chinese language as used in Taiwan. + * Same as TAIWAN Locale. + */ + public static final Locale TRADITIONAL_CHINESE = getLocale("zh", "TW"); + + /** Locale which represents France. */ + public static final Locale FRANCE = getLocale("fr", "FR"); + + /** Locale which represents Germany. */ + public static final Locale GERMANY = getLocale("de", "DE"); + + /** Locale which represents Italy. */ + public static final Locale ITALY = getLocale("it", "IT"); + + /** Locale which represents Japan. */ + public static final Locale JAPAN = getLocale("ja", "JP"); + + /** Locale which represents Korea. */ + public static final Locale KOREA = getLocale("ko", "KR"); + + /** + * Locale which represents China. + * Same as SIMPLIFIED_CHINESE Locale. + */ + public static final Locale CHINA = SIMPLIFIED_CHINESE; + + /** + * Locale which represents the People's Republic of China. + * Same as CHINA Locale. + */ + public static final Locale PRC = CHINA; + + /** + * Locale which represents Taiwan. + * Same as TRADITIONAL_CHINESE Locale. + */ + public static final Locale TAIWAN = TRADITIONAL_CHINESE; + + /** Locale which represents the United Kingdom. */ + public static final Locale UK = getLocale("en", "GB"); + + /** Locale which represents the United States. */ + public static final Locale US = getLocale("en", "US"); + + /** Locale which represents the English speaking portion of Canada. */ + public static final Locale CANADA = getLocale("en", "CA"); + + /** Locale which represents the French speaking portion of Canada. */ + public static final Locale CANADA_FRENCH = getLocale("fr", "CA"); + + /** + * Compatible with JDK 1.1+. + */ + private static final long serialVersionUID = 9149081749638150636L; + + /** + * The language code, as returned by getLanguage(). + * + * @serial the languange, possibly "" + */ + private String language; + + /** + * The country code, as returned by getCountry(). + * + * @serial the country, possibly "" + */ + private String country; + + /** + * The variant code, as returned by getVariant(). + * + * @serial the variant, possibly "" + */ + private String variant; + + /** + * This is the cached hashcode. When writing to stream, we write -1. + * + * @serial should be -1 in serial streams + */ + private int hashcode; + + /** + * The default locale. Except for during bootstrapping, this should never be + * null. Note the logic in the main constructor, to detect when + * bootstrapping has completed. + */ + private static Locale defaultLocale = + getLocale(SystemProperties.getProperty("user.language", "en"), + SystemProperties.getProperty("user.region", ""), + SystemProperties.getProperty("user.variant", "")); + + /** + * Retrieves the locale with the specified language from the cache. + * + * @param language the language of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language) + { + return getLocale(language, "", ""); + } + + /** + * Retrieves the locale with the specified language and region + * from the cache. + * + * @param language the language of the locale to retrieve. + * @param region the region of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language, String region) + { + return getLocale(language, region, ""); + } + + /** + * Retrieves the locale with the specified language, region + * and variant from the cache. + * + * @param language the language of the locale to retrieve. + * @param region the region of the locale to retrieve. + * @param variant the variant of the locale to retrieve. + * @return the locale. + */ + private static Locale getLocale(String language, String region, String variant) + { + return new Locale(language, region, variant); + } + + /** + * Convert new iso639 codes to the old ones. + * + * @param language the language to check + * @return the appropriate code + */ + private String convertLanguage(String language) + { + if (language.equals("")) + return language; + language = language.toLowerCase(); + int index = "he,id,yi".indexOf(language); + if (index != -1) + return "iw,in,ji".substring(index, index + 2); + return language; + } + + /** + * Creates a new locale for the given language and country. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @param country uppercase two-letter ISO-3166 A2 contry code + * @param variant vendor and browser specific + * @throws NullPointerException if any argument is null + */ + public Locale(String language, String country, String variant) + { + // During bootstrap, we already know the strings being passed in are + // the correct capitalization, and not null. We can't call + // String.toUpperCase during this time, since that depends on the + // default locale. + if (defaultLocale != null) + { + language = convertLanguage(language).intern(); + country = country.toUpperCase().intern(); + variant = variant.intern(); + } + this.language = language; + this.country = country; + this.variant = variant; + hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + } + + /** + * Creates a new locale for the given language and country. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @param country uppercase two-letter ISO-3166 A2 country code + * @throws NullPointerException if either argument is null + */ + public Locale(String language, String country) + { + this(language, country, ""); + } + + /** + * Creates a new locale for a language. + * + * @param language lowercase two-letter ISO-639 A2 language code + * @throws NullPointerException if either argument is null + * @since 1.4 + */ + public Locale(String language) + { + this(language, "", ""); + } + + /** + * Returns the default Locale. The default locale is generally once set + * on start up and then never changed. Normally you should use this locale + * for everywhere you need a locale. The initial setting matches the + * default locale, the user has chosen. + * + * @return the default locale for this virtual machine + */ + public static Locale getDefault() + { + return defaultLocale; + } + + /** + * Changes the default locale. Normally only called on program start up. + * Note that this doesn't change the locale for other programs. This has + * a security check, + * <code>PropertyPermission("user.language", "write")</code>, because of + * its potential impact to running code. + * + * @param newLocale the new default locale + * @throws NullPointerException if newLocale is null + * @throws SecurityException if permission is denied + */ + public static void setDefault(Locale newLocale) + { + if (newLocale == null) + throw new NullPointerException(); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission("user.language", "write")); + defaultLocale = newLocale; + } + + /** + * Returns the list of available locales. + * + * @return the installed locales + */ + public static Locale[] getAvailableLocales() + { + /* I only return those for which localized language + * or country information exists. + * XXX - remove hard coded list, and implement more locales (Sun's JDK 1.4 + * has 148 installed locales!). + */ + return new Locale[] + { + ENGLISH, FRENCH, GERMAN, new Locale("ga", "") + }; + } + + /** + * Returns a list of all 2-letter uppercase country codes as defined + * in ISO 3166. + * + * @return a list of acceptable country codes + */ + public static String[] getISOCountries() + { + return new String[] + { + "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AN", "AO", "AQ", "AR", "AS", + "AT", "AU", "AW", "AZ", "BA", "BB", "BD", "BE", "BF", "BG", "BH", "BI", + "BJ", "BM", "BN", "BO", "BR", "BS", "BT", "BV", "BW", "BY", "BZ", "CA", + "CC", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", + "CV", "CX", "CY", "CZ", "DE", "DJ", "DK", "DM", "DO", "DZ", "EC", "EE", + "EG", "EH", "ER", "ES", "ET", "FI", "FJ", "FK", "FM", "FO", "FR", "FX", + "GA", "GB", "GD", "GE", "GF", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", + "GR", "GS", "GT", "GU", "GW", "GY", "HK", "HM", "HN", "HR", "HT", "HU", + "ID", "IE", "IL", "IN", "IO", "IQ", "IR", "IS", "IT", "JM", "JO", "JP", + "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA", + "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", + "MD", "MG", "MH", "MK", "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", + "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE", "NF", "NG", + "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", + "PH", "PK", "PL", "PM", "PN", "PR", "PT", "PW", "PY", "QA", "RE", "RO", + "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG", "SH", "SI", "SJ", "SK", + "SL", "SM", "SN", "SO", "SR", "ST", "SV", "SY", "SZ", "TC", "TD", "TF", + "TG", "TH", "TJ", "TK", "TM", "TN", "TO", "TP", "TR", "TT", "TV", "TW", + "TZ", "UA", "UG", "UM", "US", "UY", "UZ", "VA", "VC", "VE", "VG", "VI", + "VN", "VU", "WF", "WS", "YE", "YT", "YU", "ZA", "ZM", "ZR", "ZW" + }; + } + + /** + * Returns a list of all 2-letter lowercase language codes as defined + * in ISO 639 (both old and new variant). + * + * @return a list of acceptable language codes + */ + public static String[] getISOLanguages() + { + return new String[] + { + "aa", "ab", "af", "am", "ar", "as", "ay", "az", "ba", "be", "bg", "bh", + "bi", "bn", "bo", "br", "ca", "co", "cs", "cy", "da", "de", "dz", "el", + "en", "eo", "es", "et", "eu", "fa", "fi", "fj", "fo", "fr", "fy", "ga", + "gd", "gl", "gn", "gu", "ha", "he", "hi", "hr", "hu", "hy", "ia", "id", + "ie", "ik", "in", "is", "it", "iu", "iw", "ja", "ji", "jw", "ka", "kk", + "kl", "km", "kn", "ko", "ks", "ku", "ky", "la", "ln", "lo", "lt", "lv", + "mg", "mi", "mk", "ml", "mn", "mo", "mr", "ms", "mt", "my", "na", "ne", + "nl", "no", "oc", "om", "or", "pa", "pl", "ps", "pt", "qu", "rm", "rn", + "ro", "ru", "rw", "sa", "sd", "sg", "sh", "si", "sk", "sl", "sm", "sn", + "so", "sq", "sr", "ss", "st", "su", "sv", "sw", "ta", "te", "tg", "th", + "ti", "tk", "tl", "tn", "to", "tr", "ts", "tt", "tw", "ug", "uk", "ur", + "uz", "vi", "vo", "wo", "xh", "yi", "yo", "za", "zh", "zu" + }; + } + + /** + * Returns the language code of this locale. Some language codes have changed + * as ISO 639 has evolved; this returns the old name, even if you built + * the locale with the new one. + * + * @return language code portion of this locale, or an empty String + */ + public String getLanguage() + { + return language; + } + + /** + * Returns the country code of this locale. + * + * @return country code portion of this locale, or an empty String + */ + public String getCountry() + { + return country; + } + + /** + * Returns the variant code of this locale. + * + * @return the variant code portion of this locale, or an empty String + */ + public String getVariant() + { + return variant; + } + + /** + * Gets the string representation of the current locale. This consists of + * the language, the country, and the variant, separated by an underscore. + * The variant is listed only if there is a language or country. Examples: + * "en", "de_DE", "_GB", "en_US_WIN", "de__POSIX", "fr__MAC". + * + * @return the string representation of this Locale + * @see #getDisplayName() + */ + public String toString() + { + if (language.length() == 0 && country.length() == 0) + return ""; + else if (country.length() == 0 && variant.length() == 0) + return language; + StringBuffer result = new StringBuffer(language); + result.append('_').append(country); + if (variant.length() != 0) + result.append('_').append(variant); + return result.toString(); + } + + /** + * Returns the three-letter ISO language abbrevation of this locale. + * + * @throws MissingResourceException if the three-letter code is not known + */ + public String getISO3Language() + { + // We know all strings are interned so we can use '==' for better performance. + if (language == "") + return ""; + int index + = ("aa,ab,af,am,ar,as,ay,az,ba,be,bg,bh,bi,bn,bo,br,ca,co,cs,cy,da," + + "de,dz,el,en,eo,es,et,eu,fa,fi,fj,fo,fr,fy,ga,gd,gl,gn,gu,ha,iw," + + "hi,hr,hu,hy,ia,in,ie,ik,in,is,it,iu,iw,ja,ji,jw,ka,kk,kl,km,kn," + + "ko,ks,ku,ky,la,ln,lo,lt,lv,mg,mi,mk,ml,mn,mo,mr,ms,mt,my,na,ne," + + "nl,no,oc,om,or,pa,pl,ps,pt,qu,rm,rn,ro,ru,rw,sa,sd,sg,sh,si,sk," + + "sl,sm,sn,so,sq,sr,ss,st,su,sv,sw,ta,te,tg,th,ti,tk,tl,tn,to,tr," + + "ts,tt,tw,ug,uk,ur,uz,vi,vo,wo,xh,ji,yo,za,zh,zu") + .indexOf(language); + + if (index % 3 != 0 || language.length() != 2) + throw new MissingResourceException + ("Can't find ISO3 language for " + language, + "java.util.Locale", language); + + // Don't read this aloud. These are the three letter language codes. + return + ("aarabkaframharaasmaymazebakbelbulbihbisbenbodbrecatcoscescymdandeu" + + "dzoellengepospaesteusfasfinfijfaofrafrygaigdhglggrngujhauhebhinhrv" + + "hunhyeinaindileipkindislitaikuhebjpnyidjawkatkazkalkhmkankorkaskur" + + "kirlatlinlaolitlavmlgmrimkdmalmonmolmarmsamltmyanaunepnldnorociorm" + + "oripanpolpusporquerohrunronruskinsansndsagsrpsinslkslvsmosnasomsqi" + + "srpsswsotsunsweswatamteltgkthatirtuktgltsntonturtsotattwiuigukrurd" + + "uzbvievolwolxhoyidyorzhazhozul") + .substring(index, index + 3); + } + + /** + * Returns the three-letter ISO country abbrevation of the locale. + * + * @throws MissingResourceException if the three-letter code is not known + */ + public String getISO3Country() + { + // We know all strings are interned so we can use '==' for better performance. + if (country == "") + return ""; + int index + = ("AD,AE,AF,AG,AI,AL,AM,AN,AO,AQ,AR,AS,AT,AU,AW,AZ,BA,BB,BD,BE,BF," + + "BG,BH,BI,BJ,BM,BN,BO,BR,BS,BT,BV,BW,BY,BZ,CA,CC,CF,CG,CH,CI,CK," + + "CL,CM,CN,CO,CR,CU,CV,CX,CY,CZ,DE,DJ,DK,DM,DO,DZ,EC,EE,EG,EH,ER," + + "ES,ET,FI,FJ,FK,FM,FO,FR,FX,GA,GB,GD,GE,GF,GH,GI,GL,GM,GN,GP,GQ," + + "GR,GS,GT,GU,GW,GY,HK,HM,HN,HR,HT,HU,ID,IE,IL,IN,IO,IQ,IR,IS,IT," + + "JM,JO,JP,KE,KG,KH,KI,KM,KN,KP,KR,KW,KY,KZ,LA,LB,LC,LI,LK,LR,LS," + + "LT,LU,LV,LY,MA,MC,MD,MG,MH,MK,ML,MM,MN,MO,MP,MQ,MR,MS,MT,MU,MV," + + "MW,MX,MY,MZ,NA,NC,NE,NF,NG,NI,NL,NO,NP,NR,NU,NZ,OM,PA,PE,PF,PG," + + "PH,PK,PL,PM,PN,PR,PT,PW,PY,QA,RE,RO,RU,RW,SA,SB,SC,SD,SE,SG,SH," + + "SI,SJ,SK,SL,SM,SN,SO,SR,ST,SV,SY,SZ,TC,TD,TF,TG,TH,TJ,TK,TM,TN," + + "TO,TP,TR,TT,TV,TW,TZ,UA,UG,UM,US,UY,UZ,VA,VC,VE,VG,VI,VN,VU,WF," + + "WS,YE,YT,YU,ZA,ZM,ZR,ZW") + .indexOf(country); + + if (index % 3 != 0 || country.length() != 2) + throw new MissingResourceException + ("Can't find ISO3 country for " + country, + "java.util.Locale", country); + + // Don't read this aloud. These are the three letter country codes. + return + ("ANDAREAFGATGAIAALBARMANTAGOATAARGASMAUTAUSABWAZEBIHBRBBGDBELBFABGR" + + "BHRBDIBENBMUBRNBOLBRABHSBTNBVTBWABLRBLZCANCCKCAFCOGCHECIVCOKCHLCMR" + + "CHNCOLCRICUBCPVCXRCYPCZEDEUDJIDNKDMADOMDZAECUESTEGYESHERIESPETHFIN" + + "FJIFLKFSMFROFRAFXXGABGBRGRDGEOGUFGHAGIBGRLGMBGINGLPGNQGRCSGSGTMGUM" + + "GNBGUYHKGHMDHNDHRVHTIHUNIDNIRLISRINDIOTIRQIRNISLITAJAMJORJPNKENKGZ" + + "KHMKIRCOMKNAPRKKORKWTCYMKAZLAOLBNLCALIELKALBRLSOLTULUXLVALBYMARMCO" + + "MDAMDGMHLMKDMLIMMRMNGMACMNPMTQMRTMSRMLTMUSMDVMWIMEXMYSMOZNAMNCLNER" + + "NFKNGANICNLDNORNPLNRUNIUNZLOMNPANPERPYFPNGPHLPAKPOLSPMPCNPRIPRTPLW" + + "PRYQATREUROMRUSRWASAUSLBSYCSDNSWESGPSHNSVNSJMSVKSLESMRSENSOMSURSTP" + + "SLVSYRSWZTCATCDATFTGOTHATJKTKLTKMTUNTONTMPTURTTOTUVTWNTZAUKRUGAUMI" + + "USAURYUZBVATVCTVENVGBVIRVNMVUTWLFWSMYEMMYTYUGZAFZMBZARZWE") + .substring(index, index + 3); + } + + /** + * Gets the country name suitable for display to the user, formatted + * for the default locale. This has the same effect as + * <pre> + * getDisplayLanguage(Locale.getDefault()); + * </pre> + * + * @return the language name of this locale localized to the default locale, + * with the ISO code as backup + */ + public String getDisplayLanguage() + { + return getDisplayLanguage(defaultLocale); + } + + /** + * <p> + * Gets the name of the language specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is + * <code>Locale.GERMANY</code>, and the specified locale is <code>Locale.UK</code>, + * the result would be 'German'. Using the German locale would instead give + * 'Deutsch'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + * </p> + * <ul> + * <li>the display name in the default locale</li> + * <li>the display name in English</li> + * <li>the ISO code</li> + * </ul> + * <p> + * If the language is unspecified by this locale, then the empty string is + * returned. + * </p> + * + * @param inLocale the locale to use for formatting the display string. + * @return the language name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + public String getDisplayLanguage(Locale inLocale) + { + try + { + ResourceBundle bundle + = ResourceBundle.getBundle("gnu.java.locale.iso639", inLocale); + return bundle.getString(language); + } + catch (MissingResourceException ex) + { + return language; + } + } + + /** + * Returns the country name of this locale localized to the + * default locale. If the localized is not found, the ISO code + * is returned. This has the same effect as + * <pre> + * getDisplayCountry(Locale.getDefault()); + * </pre> + * + * @return the country name of this locale localized to the given locale, + * with the ISO code as backup + */ + public String getDisplayCountry() + { + return getDisplayCountry(defaultLocale); + } + + /** + * <p> + * Gets the name of the country specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is + * <code>Locale.GERMANY</code>, and the specified locale is <code>Locale.UK</code>, + * the result would be 'Germany'. Using the German locale would instead give + * 'Deutschland'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + * </p> + * <ul> + * <li>the display name in the default locale</li> + * <li>the display name in English</li> + * <li>the ISO code</li> + * </ul> + * <p> + * If the country is unspecified by this locale, then the empty string is + * returned. + * </p> + * + * @param inLocale the locale to use for formatting the display string. + * @return the country name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + public String getDisplayCountry(Locale inLocale) + { + try + { + ResourceBundle bundle = + ResourceBundle.getBundle("gnu.java.locale.iso3166", inLocale); + return bundle.getString(country); + } + catch (MissingResourceException ex) + { + return country; + } + } + + /** + * Returns the variant name of this locale localized to the + * default locale. If the localized is not found, the variant code + * itself is returned. This has the same effect as + * <pre> + * getDisplayVariant(Locale.getDefault()); + * </pre> + * + * @return the variant code of this locale localized to the given locale, + * with the ISO code as backup + */ + public String getDisplayVariant() + { + return getDisplayVariant(defaultLocale); + } + + /** + * <p> + * Gets the name of the variant specified by this locale, in a form suitable + * for display to the user. If possible, the display name will be localized + * to the specified locale. For example, if the locale instance is a revised + * variant, and the specified locale is <code>Locale.UK</code>, the result + * would be 'REVISED'. Using the German locale would instead give + * 'Revidiert'. If the display name can not be localized to the supplied + * locale, it will fall back on other output in the following order: + * </p> + * <ul> + * <li>the display name in the default locale</li> + * <li>the display name in English</li> + * <li>the ISO code</li> + * </ul> + * <p> + * If the variant is unspecified by this locale, then the empty string is + * returned. + * </p> + * + * @param inLocale the locale to use for formatting the display string. + * @return the variant name of this locale localized to the given locale, + * with the default locale, English and the ISO code as backups. + * @throws NullPointerException if the supplied locale is null. + */ + public String getDisplayVariant(Locale inLocale) + { + // XXX - load a bundle? + return variant; + } + + /** + * Gets all local components suitable for display to the user, formatted + * for the default locale. For the language component, getDisplayLanguage + * is called. For the country component, getDisplayCountry is called. + * For the variant set component, getDisplayVariant is called. + * + * <p>The returned String will be one of the following forms:<br> + * <pre> + * language (country, variant) + * language (country) + * language (variant) + * country (variant) + * language + * country + * variant + * </pre> + * + * @return String version of this locale, suitable for display to the user + */ + public String getDisplayName() + { + return getDisplayName(defaultLocale); + } + + /** + * Gets all local components suitable for display to the user, formatted + * for a specified locale. For the language component, + * getDisplayLanguage(Locale) is called. For the country component, + * getDisplayCountry(Locale) is called. For the variant set component, + * getDisplayVariant(Locale) is called. + * + * <p>The returned String will be one of the following forms:<br> + * <pre> + * language (country, variant) + * language (country) + * language (variant) + * country (variant) + * language + * country + * variant + * </pre> + * + * @param locale locale to use for formatting + * @return String version of this locale, suitable for display to the user + */ + public String getDisplayName(Locale locale) + { + StringBuffer result = new StringBuffer(); + int count = 0; + String[] delimiters = {"", " (", ","}; + if (language.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayLanguage(locale)); + } + if (country.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayCountry(locale)); + } + if (variant.length() != 0) + { + result.append(delimiters[count++]); + result.append(getDisplayVariant(locale)); + } + if (count > 1) + result.append(")"); + return result.toString(); + } + + /** + * Does the same as <code>Object.clone()</code> but does not throw + * a <code>CloneNotSupportedException</code>. Why anyone would + * use this method is a secret to me, since this class is immutable. + * + * @return the clone + */ + public Object clone() + { + // This class is final, so no need to use native super.clone(). + return new Locale(language, country, variant); + } + + /** + * Return the hash code for this locale. The hashcode is the logical + * xor of the hash codes of the language, the country and the variant. + * The hash code is precomputed, since <code>Locale</code>s are often + * used in hash tables. + * + * @return the hashcode + */ + public int hashCode() + { + return hashcode; + } + + /** + * Compares two locales. To be equal, obj must be a Locale with the same + * language, country, and variant code. + * + * @param obj the other locale + * @return true if obj is equal to this + */ + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (! (obj instanceof Locale)) + return false; + Locale l = (Locale) obj; + + return (language == l.language + && country == l.country + && variant == l.variant); + } + + /** + * Write the locale to an object stream. + * + * @param output the stream to write to + * @throws IOException if the write fails + * @serialData The first three fields are Strings representing language, + * country, and variant. The fourth field is a placeholder for + * the cached hashcode, but this is always written as -1, and + * recomputed when reading it back. + */ + private void writeObject(ObjectOutputStream s) + throws IOException + { + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("hashcode", -1); + s.defaultWriteObject(); + } + + /** + * Reads a locale from the input stream. + * + * @param input the stream to read from + * @throws IOException if reading fails + * @throws ClassNotFoundException if reading fails + * @serialData the hashCode is always invalid and must be recomputed + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + s.defaultReadObject(); + language = language.intern(); + country = country.intern(); + variant = variant.intern(); + hashcode = language.hashCode() ^ country.hashCode() ^ variant.hashCode(); + } +} // class Locale diff --git a/gcc-4.2.1/libjava/java/util/ResourceBundle.java b/gcc-4.2.1/libjava/java/util/ResourceBundle.java new file mode 100644 index 000000000..19dd3cdf1 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/ResourceBundle.java @@ -0,0 +1,580 @@ +/* ResourceBundle -- aids in loading resource bundles + Copyright (C) 1998, 1999, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import java.io.IOException; +import java.io.InputStream; + +/** + * A resource bundle contains locale-specific data. If you need localized + * data, you can load a resource bundle that matches the locale with + * <code>getBundle</code>. Now you can get your object by calling + * <code>getObject</code> or <code>getString</code> on that bundle. + * + * <p>When a bundle is demanded for a specific locale, the ResourceBundle + * is searched in following order (<i>def. language</i> stands for the + * two letter ISO language code of the default locale (see + * <code>Locale.getDefault()</code>). + * +<pre>baseName_<i>language code</i>_<i>country code</i>_<i>variant</i> +baseName_<i>language code</i>_<i>country code</i> +baseName_<i>language code</i> +baseName_<i>def. language</i>_<i>def. country</i>_<i>def. variant</i> +baseName_<i>def. language</i>_<i>def. country</i> +baseName_<i>def. language</i> +baseName</pre> + * + * <p>A bundle is backed up by less specific bundles (omitting variant, country + * or language). But it is not backed up by the default language locale. + * + * <p>If you provide a bundle for a given locale, say + * <code>Bundle_en_UK_POSIX</code>, you must also provide a bundle for + * all sub locales, ie. <code>Bundle_en_UK</code>, <code>Bundle_en</code>, and + * <code>Bundle</code>. + * + * <p>When a bundle is searched, we look first for a class with the given + * name, then for a file with <code>.properties</code> extension in the + * classpath. The name must be a fully qualified classname (with dots as + * path separators). + * + * <p>(Note: This implementation always backs up the class with a properties + * file if that is existing, but you shouldn't rely on this, if you want to + * be compatible to the standard JDK.) + * + * @author Jochen Hoenicke + * @author Eric Blake (ebb9@email.byu.edu) + * @see Locale + * @see ListResourceBundle + * @see PropertyResourceBundle + * @since 1.1 + * @status updated to 1.4 + */ +public abstract class ResourceBundle +{ + /** + * The parent bundle. This is consulted when you call getObject and there + * is no such resource in the current bundle. This field may be null. + */ + protected ResourceBundle parent; + + /** + * The locale of this resource bundle. You can read this with + * <code>getLocale</code> and it is automatically set in + * <code>getBundle</code>. + */ + private Locale locale; + + private static native ClassLoader getCallingClassLoader(); + + /** + * The resource bundle cache. + */ + private static Map bundleCache; + + /** + * The last default Locale we saw. If this ever changes then we have to + * reset our caches. + */ + private static Locale lastDefaultLocale; + + /** + * The `empty' locale is created once in order to optimize + * tryBundle(). + */ + private static final Locale emptyLocale = new Locale(""); + + /** + * The constructor. It does nothing special. + */ + public ResourceBundle() + { + } + + /** + * Get a String from this resource bundle. Since most localized Objects + * are Strings, this method provides a convenient way to get them without + * casting. + * + * @param key the name of the resource + * @throws MissingResourceException if the resource can't be found + * @throws NullPointerException if key is null + * @throws ClassCastException if resource is not a string + */ + public final String getString(String key) + { + return (String) getObject(key); + } + + /** + * Get an array of Strings from this resource bundle. This method + * provides a convenient way to get it without casting. + * + * @param key the name of the resource + * @throws MissingResourceException if the resource can't be found + * @throws NullPointerException if key is null + * @throws ClassCastException if resource is not a string + */ + public final String[] getStringArray(String key) + { + return (String[]) getObject(key); + } + + /** + * Get an object from this resource bundle. This will call + * <code>handleGetObject</code> for this resource and all of its parents, + * until it finds a non-null resource. + * + * @param key the name of the resource + * @throws MissingResourceException if the resource can't be found + * @throws NullPointerException if key is null + */ + public final Object getObject(String key) + { + for (ResourceBundle bundle = this; bundle != null; bundle = bundle.parent) + { + Object o = bundle.handleGetObject(key); + if (o != null) + return o; + } + + String className = getClass().getName(); + throw new MissingResourceException("Key '" + key + + "'not found in Bundle: " + + className, className, key); + } + + /** + * Return the actual locale of this bundle. You can use it after calling + * getBundle, to know if the bundle for the desired locale was loaded or + * if the fall back was used. + * + * @return the bundle's locale + */ + public Locale getLocale() + { + return locale; + } + + /** + * Set the parent of this bundle. The parent is consulted when you call + * getObject and there is no such resource in the current bundle. + * + * @param parent the parent of this bundle + */ + protected void setParent(ResourceBundle parent) + { + this.parent = parent; + } + + /** + * Get the appropriate ResourceBundle for the default locale. This is like + * calling <code>getBundle(baseName, Locale.getDefault(), + * getClass().getClassLoader()</code>, except that any security check of + * getClassLoader won't fail. + * + * @param baseName the name of the ResourceBundle + * @return the desired resource bundle + * @throws MissingResourceException if the resource bundle can't be found + * @throws NullPointerException if baseName is null + */ + public static ResourceBundle getBundle(String baseName) + { + ClassLoader cl = getCallingClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + return getBundle(baseName, Locale.getDefault(), cl); + } + + /** + * Get the appropriate ResourceBundle for the given locale. This is like + * calling <code>getBundle(baseName, locale, + * getClass().getClassLoader()</code>, except that any security check of + * getClassLoader won't fail. + * + * @param baseName the name of the ResourceBundle + * @param locale A locale + * @return the desired resource bundle + * @throws MissingResourceException if the resource bundle can't be found + * @throws NullPointerException if baseName or locale is null + */ + public static ResourceBundle getBundle(String baseName, Locale locale) + { + ClassLoader cl = getCallingClassLoader(); + if (cl == null) + cl = ClassLoader.getSystemClassLoader(); + return getBundle(baseName, locale, cl); + } + + /** Cache key for the ResourceBundle cache. Resource bundles are keyed + by the combination of bundle name, locale, and class loader. */ + private static class BundleKey + { + String baseName; + Locale locale; + ClassLoader classLoader; + int hashcode; + + BundleKey() {} + + BundleKey(String s, Locale l, ClassLoader cl) + { + set(s, l, cl); + } + + void set(String s, Locale l, ClassLoader cl) + { + baseName = s; + locale = l; + classLoader = cl; + hashcode = baseName.hashCode() ^ locale.hashCode() ^ + classLoader.hashCode(); + } + + public int hashCode() + { + return hashcode; + } + + public boolean equals(Object o) + { + if (! (o instanceof BundleKey)) + return false; + BundleKey key = (BundleKey) o; + return hashcode == key.hashcode && + baseName.equals(key.baseName) && + locale.equals(key.locale) && + classLoader.equals(key.classLoader); + } + } + + /** A cache lookup key. This avoids having to a new one for every + * getBundle() call. */ + private static BundleKey lookupKey = new BundleKey(); + + /** Singleton cache entry to represent previous failed lookups. */ + private static Object nullEntry = new Object(); + + /** + * Get the appropriate ResourceBundle for the given locale. The following + * strategy is used: + * + * <p>A sequence of candidate bundle names are generated, and tested in + * this order, where the suffix 1 means the string from the specified + * locale, and the suffix 2 means the string from the default locale:</p> + * + * <ul> + * <li>baseName + "_" + language1 + "_" + country1 + "_" + variant1</li> + * <li>baseName + "_" + language1 + "_" + country1</li> + * <li>baseName + "_" + language1</li> + * <li>baseName + "_" + language2 + "_" + country2 + "_" + variant2</li> + * <li>baseName + "_" + language2 + "_" + country2</li> + * <li>baseName + "_" + language2</li> + * <li>baseName</li> + * </ul> + * + * <p>In the sequence, entries with an empty string are ignored. Next, + * <code>getBundle</code> tries to instantiate the resource bundle:</p> + * + * <ul> + * <li>First, an attempt is made to load a class in the specified classloader + * which is a subclass of ResourceBundle, and which has a public constructor + * with no arguments, via reflection.</li> + * <li>Next, a search is made for a property resource file, by replacing + * '.' with '/' and appending ".properties", and using + * ClassLoader.getResource(). If a file is found, then a + * PropertyResourceBundle is created from the file's contents.</li> + * </ul> + * If no resource bundle was found, a MissingResourceException is thrown. + * + * <p>Next, the parent chain is implemented. The remaining candidate names + * in the above sequence are tested in a similar manner, and if any results + * in a resource bundle, it is assigned as the parent of the first bundle + * using the <code>setParent</code> method (unless the first bundle already + * has a parent).</p> + * + * <p>For example, suppose the following class and property files are + * provided: MyResources.class, MyResources_fr_CH.properties, + * MyResources_fr_CH.class, MyResources_fr.properties, + * MyResources_en.properties, and MyResources_es_ES.class. The contents of + * all files are valid (that is, public non-abstract subclasses of + * ResourceBundle with public nullary constructors for the ".class" files, + * syntactically correct ".properties" files). The default locale is + * Locale("en", "UK").</p> + * + * <p>Calling getBundle with the shown locale argument values instantiates + * resource bundles from the following sources:</p> + * + * <ul> + * <li>Locale("fr", "CH"): result MyResources_fr_CH.class, parent + * MyResources_fr.properties, parent MyResources.class</li> + * <li>Locale("fr", "FR"): result MyResources_fr.properties, parent + * MyResources.class</li> + * <li>Locale("de", "DE"): result MyResources_en.properties, parent + * MyResources.class</li> + * <li>Locale("en", "US"): result MyResources_en.properties, parent + * MyResources.class</li> + * <li>Locale("es", "ES"): result MyResources_es_ES.class, parent + * MyResources.class</li> + * </ul> + * + * <p>The file MyResources_fr_CH.properties is never used because it is hidden + * by MyResources_fr_CH.class.</p> + * + * @param baseName the name of the ResourceBundle + * @param locale A locale + * @param classLoader a ClassLoader + * @return the desired resource bundle + * @throws MissingResourceException if the resource bundle can't be found + * @throws NullPointerException if any argument is null + * @since 1.2 + */ + // This method is synchronized so that the cache is properly + // handled. + public static synchronized ResourceBundle getBundle + (String baseName, Locale locale, ClassLoader classLoader) + { + // If the default locale changed since the last time we were called, + // all cache entries are invalidated. + Locale defaultLocale = Locale.getDefault(); + if (defaultLocale != lastDefaultLocale) + { + bundleCache = new HashMap(); + lastDefaultLocale = defaultLocale; + } + + // This will throw NullPointerException if any arguments are null. + lookupKey.set(baseName, locale, classLoader); + + Object obj = bundleCache.get(lookupKey); + ResourceBundle rb = null; + + if (obj instanceof ResourceBundle) + { + return (ResourceBundle) obj; + } + else if (obj == nullEntry) + { + // Lookup has failed previously. Fall through. + } + else + { + // First, look for a bundle for the specified locale. We don't want + // the base bundle this time. + boolean wantBase = locale.equals(defaultLocale); + ResourceBundle bundle = tryBundle(baseName, locale, classLoader, + wantBase); + + // Try the default locale if neccessary. + if (bundle == null && !locale.equals(defaultLocale)) + bundle = tryBundle(baseName, defaultLocale, classLoader, true); + + BundleKey key = new BundleKey(baseName, locale, classLoader); + if (bundle == null) + { + // Cache the fact that this lookup has previously failed. + bundleCache.put(key, nullEntry); + } + else + { + // Cache the result and return it. + bundleCache.put(key, bundle); + return bundle; + } + } + + throw new MissingResourceException("Bundle " + baseName + " not found", + baseName, ""); + } + + /** + * Override this method to provide the resource for a keys. This gets + * called by <code>getObject</code>. If you don't have a resource + * for the given key, you should return null instead throwing a + * MissingResourceException. You don't have to ask the parent, getObject() + * already does this; nor should you throw a MissingResourceException. + * + * @param key the key of the resource + * @return the resource for the key, or null if not in bundle + * @throws NullPointerException if key is null + */ + protected abstract Object handleGetObject(String key); + + /** + * This method should return all keys for which a resource exists; you + * should include the enumeration of any parent's keys, after filtering out + * duplicates. + * + * @return an enumeration of the keys + */ + public abstract Enumeration getKeys(); + + /** + * Tries to load a class or a property file with the specified name. + * + * @param localizedName the name + * @param classloader the classloader + * @return the resource bundle if it was loaded, otherwise the backup + */ + private static ResourceBundle tryBundle(String localizedName, + ClassLoader classloader) + { + ResourceBundle bundle = null; + try + { + Class rbClass; + if (classloader == null) + rbClass = Class.forName(localizedName); + else + rbClass = classloader.loadClass(localizedName); + // Note that we do the check up front instead of catching + // ClassCastException. The reason for this is that some crazy + // programs (Eclipse) have classes that do not extend + // ResourceBundle but that have the same name as a property + // bundle; in fact Eclipse relies on ResourceBundle not + // instantiating these classes. + if (ResourceBundle.class.isAssignableFrom(rbClass)) + bundle = (ResourceBundle) rbClass.newInstance(); + } + catch (IllegalAccessException ex) {} + catch (InstantiationException ex) {} + catch (ClassNotFoundException ex) {} + + if (bundle == null) + { + try + { + InputStream is; + String resourceName + = localizedName.replace('.', '/') + ".properties"; + if (classloader == null) + is = ClassLoader.getSystemResourceAsStream(resourceName); + else + is = classloader.getResourceAsStream(resourceName); + if (is != null) + bundle = new PropertyResourceBundle(is); + } + catch (IOException ex) + { + MissingResourceException mre = new MissingResourceException + ("Failed to load bundle: " + localizedName, localizedName, ""); + mre.initCause(ex); + throw mre; + } + } + + return bundle; + } + + /** + * Tries to load a the bundle for a given locale, also loads the backup + * locales with the same language. + * + * @param baseName the raw bundle name, without locale qualifiers + * @param locale the locale + * @param classloader the classloader + * @param bundle the backup (parent) bundle + * @param wantBase whether a resource bundle made only from the base name + * (with no locale information attached) should be returned. + * @return the resource bundle if it was loaded, otherwise the backup + */ + private static ResourceBundle tryBundle(String baseName, Locale locale, + ClassLoader classLoader, + boolean wantBase) + { + String language = locale.getLanguage(); + String country = locale.getCountry(); + String variant = locale.getVariant(); + + int baseLen = baseName.length(); + + // Build up a StringBuffer containing the complete bundle name, fully + // qualified by locale. + StringBuffer sb = new StringBuffer(baseLen + variant.length() + 7); + + sb.append(baseName); + + if (language.length() > 0) + { + sb.append('_'); + sb.append(language); + + if (country.length() > 0) + { + sb.append('_'); + sb.append(country); + + if (variant.length() > 0) + { + sb.append('_'); + sb.append(variant); + } + } + } + + // Now try to load bundles, starting with the most specialized name. + // Build up the parent chain as we go. + String bundleName = sb.toString(); + ResourceBundle first = null; // The most specialized bundle. + ResourceBundle last = null; // The least specialized bundle. + + while (true) + { + ResourceBundle foundBundle = tryBundle(bundleName, classLoader); + if (foundBundle != null) + { + if (first == null) + first = foundBundle; + if (last != null) + last.parent = foundBundle; + foundBundle.locale = locale; + last = foundBundle; + } + int idx = bundleName.lastIndexOf('_'); + // Try the non-localized base name only if we already have a + // localized child bundle, or wantBase is true. + if (idx > baseLen || (idx == baseLen && (first != null || wantBase))) + bundleName = bundleName.substring(0, idx); + else + break; + } + + return first; + } +} diff --git a/gcc-4.2.1/libjava/java/util/VMTimeZone.java b/gcc-4.2.1/libjava/java/util/VMTimeZone.java new file mode 100644 index 000000000..86b625843 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/VMTimeZone.java @@ -0,0 +1,345 @@ +/* java.util.VMTimeZone + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util; + +import gnu.classpath.Configuration; + +import java.io.*; + +/** + * + */ +final class VMTimeZone +{ + static + { + if (Configuration.INIT_LOAD_LIBRARY) + { + System.loadLibrary("javautil"); + } + } + + /** + * This method returns a time zone id string which is in the form + * (standard zone name) or (standard zone name)(GMT offset) or + * (standard zone name)(GMT offset)(daylight time zone name). The + * GMT offset can be in seconds, or where it is evenly divisible by + * 3600, then it can be in hours. The offset must be the time to + * add to the local time to get GMT. If a offset is given and the + * time zone observes daylight saving then the (daylight time zone + * name) must also be given (otherwise it is assumed the time zone + * does not observe any daylight savings). + * <p> + * The result of this method is given to the method + * TimeZone.getDefaultTimeZone(String) which tries to map the time + * zone id to a known TimeZone. See that method on how the returned + * String is mapped to a real TimeZone object. + * <p> + * The reference implementation which is made for GNU/Posix like + * systems calls <code>System.getenv("TZ")</code>, + * <code>readTimeZoneFile("/etc/timezone")</code>, + * <code>readtzFile("/etc/localtime")</code> and finally + * <code>getSystemTimeZoneId()</code> till a supported TimeZone is + * found through <code>TimeZone.getDefaultTimeZone(String)</code>. + * If every method fails <code>null</code> is returned (which means + * the TimeZone code will fall back on GMT as default time zone). + * <p> + * Note that this method is called inside a + * <code>AccessController.doPrivileged()</code> block and runs with + * the priviliges of the java.util system classes. It will only be + * called when the default time zone is not yet set, the system + * property user.timezone isn't set and it is requested for the + * first time. + */ + static TimeZone getDefaultTimeZoneId() + { + TimeZone zone = null; + + // See if TZ environment variable is set and accessible. + String tzid = System.getenv("TZ"); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + + // Try to parse /etc/timezone. + if (zone == null) + { + tzid = readTimeZoneFile("/etc/timezone"); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + } + + // Try to parse /etc/localtime + if (zone == null) + { + tzid = readtzFile("/etc/localtime"); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + } + + // Try some system specific way + if (zone == null) + { + tzid = getSystemTimeZoneId(); + if (tzid != null && !tzid.equals("")) + zone = TimeZone.getDefaultTimeZone(tzid); + } + + return zone; + } + + /** + * Tries to read the time zone name from a file. Only the first + * consecutive letters, digits, slashes, dashes and underscores are + * read from the file. If the file cannot be read or an IOException + * occurs null is returned. + * <p> + * The /etc/timezone file is not standard, but a lot of systems have + * it. If it exist the first line always contains a string + * describing the timezone of the host of domain. Some systems + * contain a /etc/TIMEZONE file which is used to set the TZ + * environment variable (which is checked before /etc/timezone is + * read). + */ + private static String readTimeZoneFile(String file) + { + File f = new File(file); + if (!f.exists()) + return null; + + InputStreamReader isr = null; + try + { + FileInputStream fis = new FileInputStream(f); + BufferedInputStream bis = new BufferedInputStream(fis); + isr = new InputStreamReader(bis); + + StringBuffer sb = new StringBuffer(); + int i = isr.read(); + while (i != -1) + { + char c = (char) i; + if (Character.isLetter(c) || Character.isDigit(c) + || c == '/' || c == '-' || c == '_') + { + sb.append(c); + i = isr.read(); + } + else + break; + } + return sb.toString(); + } + catch (IOException ioe) + { + // Parse error, not a proper tzfile. + return null; + } + finally + { + try + { + if (isr != null) + isr.close(); + } + catch (IOException ioe) + { + // Error while close, nothing we can do. + } + } + } + + /** + * Tries to read a file as a "standard" tzfile and return a time + * zone id string as expected by <code>getDefaultTimeZone(String)</code>. + * If the file doesn't exist, an IOException occurs or it isn't a tzfile + * that can be parsed null is returned. + * <p> + * The tzfile structure (as also used by glibc) is described in the Olson + * tz database archive as can be found at + * <code>ftp://elsie.nci.nih.gov/pub/</code>. + * <p> + * At least the following platforms support the tzdata file format + * and /etc/localtime (GNU/Linux, Darwin, Solaris and FreeBSD at + * least). Some systems (like Darwin) don't start the file with the + * required magic bytes 'TZif', this implementation can handle + * that). + */ + private static String readtzFile(String file) + { + File f = new File(file); + if (!f.exists()) + return null; + + DataInputStream dis = null; + try + { + FileInputStream fis = new FileInputStream(f); + BufferedInputStream bis = new BufferedInputStream(fis); + dis = new DataInputStream(bis); + + // Make sure we are reading a tzfile. + byte[] tzif = new byte[4]; + dis.readFully(tzif); + if (tzif[0] == 'T' && tzif[1] == 'Z' + && tzif[2] == 'i' && tzif[3] == 'f') + // Reserved bytes, ttisgmtcnt, ttisstdcnt and leapcnt + skipFully(dis, 16 + 3 * 4); + else + // Darwin has tzdata files that don't start with the TZif marker + skipFully(dis, 16 + 3 * 4 - 4); + + int timecnt = dis.readInt(); + int typecnt = dis.readInt(); + if (typecnt > 0) + { + int charcnt = dis.readInt(); + // Transition times plus indexed transition times. + skipFully(dis, timecnt * (4 + 1)); + + // Get last gmt_offset and dst/non-dst time zone names. + int abbrind = -1; + int dst_abbrind = -1; + int gmt_offset = 0; + while (typecnt-- > 0) + { + // gmtoff + int offset = dis.readInt(); + int dst = dis.readByte(); + if (dst == 0) + { + abbrind = dis.readByte(); + gmt_offset = offset; + } + else + dst_abbrind = dis.readByte(); + } + + // gmt_offset is the offset you must add to UTC/GMT to + // get the local time, we need the offset to add to + // the local time to get UTC/GMT. + gmt_offset *= -1; + + // Turn into hours if possible. + if (gmt_offset % 3600 == 0) + gmt_offset /= 3600; + + if (abbrind >= 0) + { + byte[] names = new byte[charcnt]; + dis.readFully(names); + int j = abbrind; + while (j < charcnt && names[j] != 0) + j++; + + String zonename = new String(names, abbrind, j - abbrind, + "ASCII"); + + String dst_zonename; + if (dst_abbrind >= 0) + { + j = dst_abbrind; + while (j < charcnt && names[j] != 0) + j++; + dst_zonename = new String(names, dst_abbrind, + j - dst_abbrind, "ASCII"); + } + else + dst_zonename = ""; + + // Only use gmt offset when necessary. + // Also special case GMT+/- timezones. + String offset_string; + if ("".equals(dst_zonename) + && (gmt_offset == 0 + || zonename.startsWith("GMT+") + || zonename.startsWith("GMT-"))) + offset_string = ""; + else + offset_string = Integer.toString(gmt_offset); + + String id = zonename + offset_string + dst_zonename; + + return id; + } + } + + // Something didn't match while reading the file. + return null; + } + catch (IOException ioe) + { + // Parse error, not a proper tzfile. + return null; + } + finally + { + try + { + if (dis != null) + dis.close(); + } + catch(IOException ioe) + { + // Error while close, nothing we can do. + } + } + } + + /** + * Skips the requested number of bytes in the given InputStream. + * Throws EOFException if not enough bytes could be skipped. + * Negative numbers of bytes to skip are ignored. + */ + private static void skipFully(InputStream is, long l) throws IOException + { + while (l > 0) + { + long k = is.skip(l); + if (k <= 0) + throw new EOFException(); + l -= k; + } + } + + /** + * Tries to get the system time zone id through native code. + */ + private static native String getSystemTimeZoneId(); +} diff --git a/gcc-4.2.1/libjava/java/util/logging/LogManager.java b/gcc-4.2.1/libjava/java/util/logging/LogManager.java new file mode 100644 index 000000000..b8b31c43c --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/logging/LogManager.java @@ -0,0 +1,981 @@ +/* LogManager.java -- a class for maintaining Loggers and managing + configuration properties + Copyright (C) 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util.logging; + +import gnu.classpath.SystemProperties; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; + +/** + * The <code>LogManager</code> maintains a hierarchical namespace + * of Logger objects and manages properties for configuring the logging + * framework. There exists only one single <code>LogManager</code> + * per virtual machine. This instance can be retrieved using the + * static method {@link #getLogManager()}. + * + * <p><strong>Configuration Process:</strong> The global LogManager + * object is created and configured when the class + * <code>java.util.logging.LogManager</code> is initialized. + * The configuration process includes the subsequent steps: + * + * <ul> + * <li>If the system property <code>java.util.logging.manager</code> + * is set to the name of a subclass of + * <code>java.util.logging.LogManager</code>, an instance of + * that subclass is created and becomes the global LogManager. + * Otherwise, a new instance of LogManager is created.</li> + * <li>The <code>LogManager</code> constructor tries to create + * a new instance of the class specified by the system + * property <code>java.util.logging.config.class</code>. + * Typically, the constructor of this class will call + * <code>LogManager.getLogManager().readConfiguration(java.io.InputStream)</code> + * for configuring the logging framework. + * The configuration process stops at this point if + * the system property <code>java.util.logging.config.class</code> + * is set (irrespective of whether the class constructor + * could be called or an exception was thrown).</li> + * + * <li>If the system property <code>java.util.logging.config.class</code> + * is <em>not</em> set, the configuration parameters are read in from + * a file and passed to + * {@link #readConfiguration(java.io.InputStream)}. + * The name and location of this file are specified by the system + * property <code>java.util.logging.config.file</code>.</li> + * <li>If the system property <code>java.util.logging.config.file</code> + * is not set, however, the contents of the URL + * "{gnu.classpath.home.url}/logging.properties" are passed to + * {@link #readConfiguration(java.io.InputStream)}. + * Here, "{gnu.classpath.home.url}" stands for the value of + * the system property <code>gnu.classpath.home.url</code>.</li> + * </ul> + * + * <p>The <code>LogManager</code> has a level of <code>INFO</code> by + * default, and this will be inherited by <code>Logger</code>s unless they + * override it either by properties or programmatically. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class LogManager +{ + /** + * The object name for the logging management bean. + * @since 1.5 + */ + public static final String LOGGING_MXBEAN_NAME + = "java.util.logging:type=Logging"; + + /** + * The singleton LogManager instance. + */ + private static LogManager logManager; + + /** + * The singleton logging bean. + */ + private static LoggingMXBean loggingBean; + + /** + * The registered named loggers; maps the name of a Logger to + * a WeakReference to it. + */ + private Map loggers; + + /** + * The properties for the logging framework which have been + * read in last. + */ + private Properties properties; + + /** + * A delegate object that provides support for handling + * PropertyChangeEvents. The API specification does not + * mention which bean should be the source in the distributed + * PropertyChangeEvents, but Mauve test code has determined that + * the Sun J2SE 1.4 reference implementation uses the LogManager + * class object. This is somewhat strange, as the class object + * is not the bean with which listeners have to register, but + * there is no reason for the GNU Classpath implementation to + * behave differently from the reference implementation in + * this case. + */ + private final PropertyChangeSupport pcs = new PropertyChangeSupport( /* source bean */ + LogManager.class); + + protected LogManager() + { + loggers = new HashMap(); + } + + /** + * Returns the globally shared LogManager instance. + */ + public static synchronized LogManager getLogManager() + { + if (logManager == null) + { + logManager = makeLogManager(); + initLogManager(); + } + return logManager; + } + + private static final String MANAGER_PROPERTY = "java.util.logging.manager"; + + private static LogManager makeLogManager() + { + String managerClassName = SystemProperties.getProperty(MANAGER_PROPERTY); + LogManager manager = (LogManager) createInstance + (managerClassName, LogManager.class, MANAGER_PROPERTY); + if (manager == null) + manager = new LogManager(); + return manager; + } + + private static final String CONFIG_PROPERTY = "java.util.logging.config.class"; + + private static void initLogManager() + { + LogManager manager = getLogManager(); + Logger.root.setLevel(Level.INFO); + manager.addLogger(Logger.root); + + /* The Javadoc description of the class explains + * what is going on here. + */ + Object configurator = createInstance(System.getProperty(CONFIG_PROPERTY), + /* must be instance of */ Object.class, + CONFIG_PROPERTY); + + try + { + if (configurator == null) + manager.readConfiguration(); + } + catch (IOException ex) + { + /* FIXME: Is it ok to ignore exceptions here? */ + } + } + + /** + * Registers a listener which will be notified when the + * logging properties are re-read. + */ + public synchronized void addPropertyChangeListener(PropertyChangeListener listener) + { + /* do not register null. */ + listener.getClass(); + + pcs.addPropertyChangeListener(listener); + } + + /** + * Unregisters a listener. + * + * If <code>listener</code> has not been registered previously, + * nothing happens. Also, no exception is thrown if + * <code>listener</code> is <code>null</code>. + */ + public synchronized void removePropertyChangeListener(PropertyChangeListener listener) + { + if (listener != null) + pcs.removePropertyChangeListener(listener); + } + + /** + * Adds a named logger. If a logger with the same name has + * already been registered, the method returns <code>false</code> + * without adding the logger. + * + * <p>The <code>LogManager</code> only keeps weak references + * to registered loggers. Therefore, names can become available + * after automatic garbage collection. + * + * @param logger the logger to be added. + * + * @return <code>true</code>if <code>logger</code> was added, + * <code>false</code> otherwise. + * + * @throws NullPointerException if <code>name</code> is + * <code>null</code>. + */ + public synchronized boolean addLogger(Logger logger) + { + /* To developers thinking about to remove the 'synchronized' + * declaration from this method: Please read the comment + * in java.util.logging.Logger.getLogger(String, String) + * and make sure that whatever you change wrt. synchronization + * does not endanger thread-safety of Logger.getLogger. + * The current implementation of Logger.getLogger assumes + * that LogManager does its synchronization on the globally + * shared instance of LogManager. + */ + String name; + WeakReference ref; + + /* This will throw a NullPointerException if logger is null, + * as required by the API specification. + */ + name = logger.getName(); + + ref = (WeakReference) loggers.get(name); + if (ref != null) + { + if (ref.get() != null) + return false; + + /* There has been a logger under this name in the past, + * but it has been garbage collected. + */ + loggers.remove(ref); + } + + /* Adding a named logger requires a security permission. */ + if ((name != null) && ! name.equals("")) + checkAccess(); + + Logger parent = findAncestor(logger); + loggers.put(name, new WeakReference(logger)); + if (parent != logger.getParent()) + logger.setParent(parent); + + // The level of the newly added logger must be specified. + // The easiest case is if there is a level for exactly this logger + // in the properties. If no such level exists the level needs to be + // searched along the hirachy. So if there is a new logger 'foo.blah.blub' + // and an existing parent logger 'foo' the properties 'foo.blah.blub.level' + // and 'foo.blah.level' need to be checked. If both do not exist in the + // properties the level of the new logger is set to 'null' (i.e. it uses the + // level of its parent 'foo'). + Level logLevel = logger.getLevel(); + String searchName = name; + String parentName = parent != null ? parent.getName() : ""; + while (logLevel == null && ! searchName.equals(parentName)) + { + logLevel = getLevelProperty(searchName + ".level", logLevel); + int index = searchName.lastIndexOf('.'); + if(index > -1) + searchName = searchName.substring(0,index); + else + searchName = ""; + } + logger.setLevel(logLevel); + + /* It can happen that existing loggers should be children of + * the newly added logger. For example, assume that there + * already exist loggers under the names "", "foo", and "foo.bar.baz". + * When adding "foo.bar", the logger "foo.bar.baz" should change + * its parent to "foo.bar". + */ + for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();) + { + Logger possChild = (Logger) ((WeakReference) loggers.get(iter.next())) + .get(); + if ((possChild == null) || (possChild == logger) + || (possChild.getParent() != parent)) + continue; + + if (! possChild.getName().startsWith(name)) + continue; + + if (possChild.getName().charAt(name.length()) != '.') + continue; + + possChild.setParent(logger); + } + + return true; + } + + /** + * Finds the closest ancestor for a logger among the currently + * registered ones. For example, if the currently registered + * loggers have the names "", "foo", and "foo.bar", the result for + * "foo.bar.baz" will be the logger whose name is "foo.bar". + * + * @param child a logger for whose name no logger has been + * registered. + * + * @return the closest ancestor for <code>child</code>, + * or <code>null</code> if <code>child</code> + * is the root logger. + * + * @throws NullPointerException if <code>child</code> + * is <code>null</code>. + */ + private synchronized Logger findAncestor(Logger child) + { + String childName = child.getName(); + int childNameLength = childName.length(); + Logger best = Logger.root; + int bestNameLength = 0; + + Logger cand; + String candName; + int candNameLength; + + if (child == Logger.root) + return null; + + for (Iterator iter = loggers.keySet().iterator(); iter.hasNext();) + { + candName = (String) iter.next(); + candNameLength = candName.length(); + + if (candNameLength > bestNameLength + && childNameLength > candNameLength + && childName.startsWith(candName) + && childName.charAt(candNameLength) == '.') + { + cand = (Logger) ((WeakReference) loggers.get(candName)).get(); + if ((cand == null) || (cand == child)) + continue; + + bestNameLength = candName.length(); + best = cand; + } + } + + return best; + } + + /** + * Returns a Logger given its name. + * + * @param name the name of the logger. + * + * @return a named Logger, or <code>null</code> if there is no + * logger with that name. + * + * @throw java.lang.NullPointerException if <code>name</code> + * is <code>null</code>. + */ + public synchronized Logger getLogger(String name) + { + WeakReference ref; + + /* Throw a NullPointerException if name is null. */ + name.getClass(); + + ref = (WeakReference) loggers.get(name); + if (ref != null) + return (Logger) ref.get(); + else + return null; + } + + /** + * Returns an Enumeration of currently registered Logger names. + * Since other threads can register loggers at any time, the + * result could be different any time this method is called. + * + * @return an Enumeration with the names of the currently + * registered Loggers. + */ + public synchronized Enumeration getLoggerNames() + { + return Collections.enumeration(loggers.keySet()); + } + + /** + * Resets the logging configuration by removing all handlers for + * registered named loggers and setting their level to <code>null</code>. + * The level of the root logger will be set to <code>Level.INFO</code>. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public synchronized void reset() throws SecurityException + { + /* Throw a SecurityException if the caller does not have the + * permission to control the logging infrastructure. + */ + checkAccess(); + + properties = new Properties(); + + Iterator iter = loggers.values().iterator(); + while (iter.hasNext()) + { + WeakReference ref; + Logger logger; + + ref = (WeakReference) iter.next(); + if (ref != null) + { + logger = (Logger) ref.get(); + + if (logger == null) + iter.remove(); + else if (logger != Logger.root) + { + logger.resetLogger(); + logger.setLevel(null); + } + } + } + + Logger.root.setLevel(Level.INFO); + Logger.root.resetLogger(); + } + + /** + * Configures the logging framework by reading a configuration file. + * The name and location of this file are specified by the system + * property <code>java.util.logging.config.file</code>. If this + * property is not set, the URL + * "{gnu.classpath.home.url}/logging.properties" is taken, where + * "{gnu.classpath.home.url}" stands for the value of the system + * property <code>gnu.classpath.home.url</code>. + * + * <p>The task of configuring the framework is then delegated to + * {@link #readConfiguration(java.io.InputStream)}, which will + * notify registered listeners after having read the properties. + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure, or if the caller is + * not granted the permission to read the configuration + * file. + * + * @throws IOException if there is a problem reading in the + * configuration file. + */ + public synchronized void readConfiguration() + throws IOException, SecurityException + { + String path; + InputStream inputStream; + + path = System.getProperty("java.util.logging.config.file"); + if ((path == null) || (path.length() == 0)) + { + String url = (System.getProperty("gnu.classpath.home.url") + + "/logging.properties"); + try + { + inputStream = new URL(url).openStream(); + } + catch (Exception e) + { + inputStream=null; + } + + // If no config file could be found use a default configuration. + if(inputStream == null) + { + String defaultConfig = "handlers = java.util.logging.ConsoleHandler \n" + + ".level=INFO \n"; + inputStream = new ByteArrayInputStream(defaultConfig.getBytes()); + } + } + else + inputStream = new java.io.FileInputStream(path); + + try + { + readConfiguration(inputStream); + } + finally + { + // Close the stream in order to save + // resources such as file descriptors. + inputStream.close(); + } + } + + public synchronized void readConfiguration(InputStream inputStream) + throws IOException, SecurityException + { + Properties newProperties; + Enumeration keys; + + checkAccess(); + newProperties = new Properties(); + newProperties.load(inputStream); + reset(); + this.properties = newProperties; + keys = newProperties.propertyNames(); + + while (keys.hasMoreElements()) + { + String key = ((String) keys.nextElement()).trim(); + String value = newProperties.getProperty(key); + + if (value == null) + continue; + + value = value.trim(); + + if ("handlers".equals(key)) + { + StringTokenizer tokenizer = new StringTokenizer(value); + while (tokenizer.hasMoreTokens()) + { + String handlerName = tokenizer.nextToken(); + Handler handler = (Handler) + createInstance(handlerName, Handler.class, key); + Logger.root.addHandler(handler); + } + } + + if (key.endsWith(".level")) + { + String loggerName = key.substring(0, key.length() - 6); + Logger logger = getLogger(loggerName); + + if (logger == null) + { + logger = Logger.getLogger(loggerName); + addLogger(logger); + } + Level level = null; + try + { + level = Level.parse(value); + } + catch (IllegalArgumentException e) + { + warn("bad level \'" + value + "\'", e); + } + if (level != null) + { + logger.setLevel(level); + } + continue; + } + } + + /* The API specification does not talk about the + * property name that is distributed with the + * PropertyChangeEvent. With test code, it could + * be determined that the Sun J2SE 1.4 reference + * implementation uses null for the property name. + */ + pcs.firePropertyChange(null, null, null); + } + + /** + * Returns the value of a configuration property as a String. + */ + public synchronized String getProperty(String name) + { + if (properties != null) + return properties.getProperty(name); + else + return null; + } + + /** + * Returns the value of a configuration property as an integer. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is <em>not</em> specified in the + * logging API. + * + * @param name the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if its value is not an integer + * number. + */ + static int getIntProperty(String name, int defaultValue) + { + try + { + return Integer.parseInt(getLogManager().getProperty(name)); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns the value of a configuration property as an integer, + * provided it is inside the acceptable range. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is <em>not</em> specified in the + * logging API. + * + * @param name the name of the configuration property. + * + * @param minValue the lowest acceptable value. + * + * @param maxValue the highest acceptable value. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if its value is not an integer + * number, or if it is less than the minimum value, + * or if it is greater than the maximum value. + */ + static int getIntPropertyClamped(String name, int defaultValue, + int minValue, int maxValue) + { + int val = getIntProperty(name, defaultValue); + if ((val < minValue) || (val > maxValue)) + val = defaultValue; + return val; + } + + /** + * Returns the value of a configuration property as a boolean. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is <em>not</em> specified in the + * logging API. + * + * @param name the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if its value is neither + * <code>"true"</code> nor <code>"false"</code>. + */ + static boolean getBooleanProperty(String name, boolean defaultValue) + { + try + { + return (Boolean.valueOf(getLogManager().getProperty(name))).booleanValue(); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns the value of a configuration property as a Level. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is <em>not</em> specified in the + * logging API. + * + * @param propertyName the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if + * {@link Level#parse(java.lang.String)} does not like + * the property value. + */ + static Level getLevelProperty(String propertyName, Level defaultValue) + { + try + { + return Level.parse(getLogManager().getProperty(propertyName)); + } + catch (Exception ex) + { + return defaultValue; + } + } + + /** + * Returns the value of a configuration property as a Class. + * This function is a helper used by the Classpath implementation + * of java.util.logging, it is <em>not</em> specified in the + * logging API. + * + * @param propertyName the name of the configuration property. + * + * @param defaultValue the value that will be returned if the + * property is not defined, or if it does not specify + * the name of a loadable class. + */ + static final Class getClassProperty(String propertyName, Class defaultValue) + { + String propertyValue = logManager.getProperty(propertyName); + + if (propertyValue != null) + try + { + return locateClass(propertyValue); + } + catch (ClassNotFoundException e) + { + warn(propertyName + " = " + propertyValue, e); + } + + return defaultValue; + } + + static final Object getInstanceProperty(String propertyName, Class ofClass, + Class defaultClass) + { + Class klass = getClassProperty(propertyName, defaultClass); + if (klass == null) + return null; + + try + { + Object obj = klass.newInstance(); + if (ofClass.isInstance(obj)) + return obj; + } + catch (InstantiationException e) + { + warn(propertyName + " = " + klass.getName(), e); + } + catch (IllegalAccessException e) + { + warn(propertyName + " = " + klass.getName(), e); + } + + if (defaultClass == null) + return null; + + try + { + return defaultClass.newInstance(); + } + catch (java.lang.InstantiationException ex) + { + throw new RuntimeException(ex.getMessage()); + } + catch (java.lang.IllegalAccessException ex) + { + throw new RuntimeException(ex.getMessage()); + } + } + + /** + * An instance of <code>LoggingPermission("control")</code> + * that is shared between calls to <code>checkAccess()</code>. + */ + private static final LoggingPermission controlPermission = new LoggingPermission("control", + null); + + /** + * Checks whether the current security context allows changing + * the configuration of the logging framework. For the security + * context to be trusted, it has to be granted + * a LoggingPermission("control"). + * + * @throws SecurityException if a security manager exists and + * the caller is not granted the permission to control + * the logging infrastructure. + */ + public void checkAccess() throws SecurityException + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(controlPermission); + } + + /** + * Creates a new instance of a class specified by name and verifies + * that it is an instance (or subclass of) a given type. + * + * @param className the name of the class of which a new instance + * should be created. + * + * @param type the object created must be an instance of + * <code>type</code> or any subclass of <code>type</code> + * + * @param property the system property to reference in error + * messages + * + * @return the new instance, or <code>null</code> if + * <code>className</code> is <code>null</code>, if no class + * with that name could be found, if there was an error + * loading that class, or if the constructor of the class + * has thrown an exception. + */ + private static final Object createInstance(String className, Class type, + String property) + { + Class klass = null; + + if ((className == null) || (className.length() == 0)) + return null; + + try + { + klass = locateClass(className); + if (type.isAssignableFrom(klass)) + return klass.newInstance(); + warn(property, className, "not an instance of " + type.getName()); + } + catch (ClassNotFoundException e) + { + warn(property, className, "class not found", e); + } + catch (IllegalAccessException e) + { + warn(property, className, "illegal access", e); + } + catch (InstantiationException e) + { + warn(property, className, e); + } + catch (java.lang.LinkageError e) + { + warn(property, className, "linkage error", e); + } + + return null; + } + + private static final void warn(String property, String klass, Throwable t) + { + warn(property, klass, null, t); + } + + private static final void warn(String property, String klass, String msg) + { + warn(property, klass, msg, null); + } + + private static final void warn(String property, String klass, String msg, + Throwable t) + { + warn("error instantiating '" + klass + "' referenced by " + property + + (msg == null ? "" : ", " + msg), t); + } + + /** + * All debug warnings go through this method. + */ + + private static final void warn(String msg, Throwable t) + { + System.err.println("WARNING: " + msg); + if (t != null) + t.printStackTrace(System.err); + } + + /** + * Locates a class by first checking the system class loader and + * then checking the context class loader. + * + * @param name the fully qualified name of the Class to locate + * @return Class the located Class + */ + + private static Class locateClass(String name) throws ClassNotFoundException + { + // GCJ LOCAL + // Unfortunately this can be called during bootstrap when + // Thread.currentThread() will return null. + // See bug #27658 + Thread t = Thread.currentThread(); + ClassLoader loader = (t == null) ? null : t.getContextClassLoader(); + try + { + return Class.forName(name, true, loader); + } + catch (ClassNotFoundException e) + { + loader = ClassLoader.getSystemClassLoader(); + return Class.forName(name, true, loader); + } + } + + /** + * Return the logging bean. There is a single logging bean per + * VM instance. + * @since 1.5 + */ + public static synchronized LoggingMXBean getLoggingMXBean() + { + if (loggingBean == null) + { + loggingBean = new LoggingMXBean() + { + public String getLoggerLevel(String logger) + { + LogManager mgr = getLogManager(); + Logger l = mgr.getLogger(logger); + if (l == null) + return null; + Level lev = l.getLevel(); + if (lev == null) + return ""; + return lev.getName(); + } + + public List getLoggerNames() + { + LogManager mgr = getLogManager(); + // This is inefficient, but perhaps better for maintenance. + return Collections.list(mgr.getLoggerNames()); + } + + public String getParentLoggerName(String logger) + { + LogManager mgr = getLogManager(); + Logger l = mgr.getLogger(logger); + if (l == null) + return null; + l = l.getParent(); + if (l == null) + return ""; + return l.getName(); + } + + public void setLoggerLevel(String logger, String level) + { + LogManager mgr = getLogManager(); + Logger l = mgr.getLogger(logger); + if (l == null) + throw new IllegalArgumentException("no logger named " + logger); + Level newLevel; + if (level == null) + newLevel = null; + else + newLevel = Level.parse(level); + l.setLevel(newLevel); + } + }; + } + return loggingBean; + } +} diff --git a/gcc-4.2.1/libjava/java/util/logging/Logger.java b/gcc-4.2.1/libjava/java/util/logging/Logger.java new file mode 100644 index 000000000..adb07ecf6 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/logging/Logger.java @@ -0,0 +1,1206 @@ +/* Logger.java -- a class for logging messages + Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.util.logging; + +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.security.AccessController; +import java.security.PrivilegedAction; + +/** + * A Logger is used for logging information about events. Usually, there + * is a seprate logger for each subsystem or component, although there + * is a shared instance for components that make only occasional use of + * the logging framework. + * + * <p>It is common to name a logger after the name of a corresponding + * Java package. Loggers are organized into a hierarchical namespace; + * for example, the logger <code>"org.gnu.foo"</code> is the + * <em>parent</em> of logger <code>"org.gnu.foo.bar"</code>. + * + * <p>A logger for a named subsystem can be obtained through {@link + * java.util.logging.Logger#getLogger(java.lang.String)}. However, + * only code which has been granted the permission to control the + * logging infrastructure will be allowed to customize that logger. + * Untrusted code can obtain a private, anonymous logger through + * {@link #getAnonymousLogger()} if it wants to perform any + * modifications to the logger. + * + * <p>FIXME: Write more documentation. + * + * @author Sascha Brawer (brawer@acm.org) + */ +public class Logger +{ + + static final Logger root = new Logger("", null); + + /** + * A logger provided to applications that make only occasional use + * of the logging framework, typically early prototypes. Serious + * products are supposed to create and use their own Loggers, so + * they can be controlled individually. + */ + public static final Logger global; + + static + { + // Our class might be initialized from an unprivileged context + global = (Logger) AccessController.doPrivileged + (new PrivilegedAction() + { + public Object run() + { + return getLogger("global"); + } + }); + } + + + /** + * The name of the Logger, or <code>null</code> if the logger is + * anonymous. + * + * <p>A previous version of the GNU Classpath implementation granted + * untrusted code the permission to control any logger whose name + * was null. However, test code revealed that the Sun J2SE 1.4 + * reference implementation enforces the security control for any + * logger that was not created through getAnonymousLogger, even if + * it has a null name. Therefore, a separate flag {@link + * Logger#anonymous} was introduced. + */ + private final String name; + + + /** + * The name of the resource bundle used for localization. + * + * <p>This variable cannot be declared as <code>final</code> + * because its value can change as a result of calling + * getLogger(String,String). + */ + private String resourceBundleName; + + + /** + * The resource bundle used for localization. + * + * <p>This variable cannot be declared as <code>final</code> + * because its value can change as a result of calling + * getLogger(String,String). + */ + private ResourceBundle resourceBundle; + + private Filter filter; + + private final List handlerList = new java.util.ArrayList(4); + private Handler[] handlers = new Handler[0]; + + /** + * Indicates whether or not this logger is anonymous. While + * a LoggingPermission is required for any modifications to + * a normal logger, untrusted code can obtain an anonymous logger + * and modify it according to its needs. + * + * <p>A previous version of the GNU Classpath implementation + * granted access to every logger whose name was null. + * However, test code revealed that the Sun J2SE 1.4 reference + * implementation enforces the security control for any logger + * that was not created through getAnonymousLogger, even + * if it has a null name. + */ + private boolean anonymous; + + + private boolean useParentHandlers; + + private Level level; + + private Logger parent; + + /** + * Constructs a Logger for a subsystem. Most applications do not + * need to create new Loggers explicitly; instead, they should call + * the static factory methods + * {@link #getLogger(java.lang.String,java.lang.String) getLogger} + * (with ResourceBundle for localization) or + * {@link #getLogger(java.lang.String) getLogger} (without + * ResourceBundle), respectively. + * + * @param name the name for the logger, for example "java.awt" + * or "com.foo.bar". The name should be based on + * the name of the package issuing log records + * and consist of dot-separated Java identifiers. + * + * @param resourceBundleName the name of a resource bundle + * for localizing messages, or <code>null</code> + * to indicate that messages do not need to be localized. + * + * @throws java.util.MissingResourceException if + * <code>resourceBundleName</code> is not <code>null</code> + * and no such bundle could be located. + */ + protected Logger(String name, String resourceBundleName) + throws MissingResourceException + { + this.name = name; + this.resourceBundleName = resourceBundleName; + + if (resourceBundleName == null) + resourceBundle = null; + else + resourceBundle = ResourceBundle.getBundle(resourceBundleName); + + level = null; + + /* This is null when the root logger is being constructed, + * and the root logger afterwards. + */ + parent = root; + + useParentHandlers = (parent != null); + } + + + + /** + * Finds a registered logger for a subsystem, or creates one in + * case no logger has been registered yet. + * + * @param name the name for the logger, for example "java.awt" + * or "com.foo.bar". The name should be based on + * the name of the package issuing log records + * and consist of dot-separated Java identifiers. + * + * @throws IllegalArgumentException if a logger for the subsystem + * identified by <code>name</code> has already been created, + * but uses a a resource bundle for localizing messages. + * + * @throws NullPointerException if <code>name</code> is + * <code>null</code>. + * + * @return a logger for the subsystem specified by <code>name</code> + * that does not localize messages. + */ + public static Logger getLogger(String name) + { + return getLogger(name, null); + } + + + /** + * Finds a registered logger for a subsystem, or creates one in case + * no logger has been registered yet. + * + * <p>If a logger with the specified name has already been + * registered, the behavior depends on the resource bundle that is + * currently associated with the existing logger. + * + * <ul><li>If the existing logger uses the same resource bundle as + * specified by <code>resourceBundleName</code>, the existing logger + * is returned.</li> + * + * <li>If the existing logger currently does not localize messages, + * the existing logger is modified to use the bundle specified by + * <code>resourceBundleName</code>. The existing logger is then + * returned. Therefore, all subsystems currently using this logger + * will produce localized messages from now on.</li> + * + * <li>If the existing logger already has an associated resource + * bundle, but a different one than specified by + * <code>resourceBundleName</code>, an + * <code>IllegalArgumentException</code> is thrown.</li></ul> + * + * @param name the name for the logger, for example "java.awt" + * or "org.gnu.foo". The name should be based on + * the name of the package issuing log records + * and consist of dot-separated Java identifiers. + * + * @param resourceBundleName the name of a resource bundle + * for localizing messages, or <code>null</code> + * to indicate that messages do not need to be localized. + * + * @return a logger for the subsystem specified by <code>name</code>. + * + * @throws java.util.MissingResourceException if + * <code>resourceBundleName</code> is not <code>null</code> + * and no such bundle could be located. + * + * @throws IllegalArgumentException if a logger for the subsystem + * identified by <code>name</code> has already been created, + * but uses a different resource bundle for localizing + * messages. + * + * @throws NullPointerException if <code>name</code> is + * <code>null</code>. + */ + public static Logger getLogger(String name, String resourceBundleName) + { + LogManager lm = LogManager.getLogManager(); + Logger result; + + /* Throw NullPointerException if name is null. */ + name.getClass(); + + /* Without synchronized(lm), it could happen that another thread + * would create a logger between our calls to getLogger and + * addLogger. While addLogger would indicate this by returning + * false, we could not be sure that this other logger was still + * existing when we called getLogger a second time in order + * to retrieve it -- note that LogManager is only allowed to + * keep weak references to registered loggers, so Loggers + * can be garbage collected at any time in general, and between + * our call to addLogger and our second call go getLogger + * in particular. + * + * Of course, we assume here that LogManager.addLogger etc. + * are synchronizing on the global LogManager object. There + * is a comment in the implementation of LogManager.addLogger + * referring to this comment here, so that any change in + * the synchronization of LogManager will be reflected here. + */ + synchronized (lm) + { + result = lm.getLogger(name); + if (result == null) + { + boolean couldBeAdded; + + result = new Logger(name, resourceBundleName); + couldBeAdded = lm.addLogger(result); + if (!couldBeAdded) + throw new IllegalStateException("cannot register new logger"); + } + else + { + /* The logger already exists. Make sure it uses + * the same resource bundle for localizing messages. + */ + String existingBundleName = result.getResourceBundleName(); + + /* The Sun J2SE 1.4 reference implementation will return the + * registered logger object, even if it does not have a resource + * bundle associated with it. However, it seems to change the + * resourceBundle of the registered logger to the bundle + * whose name was passed to getLogger. + */ + if ((existingBundleName == null) && (resourceBundleName != null)) + { + /* If ResourceBundle.getBundle throws an exception, the + * existing logger will be unchanged. This would be + * different if the assignment to resourceBundleName + * came first. + */ + result.resourceBundle = ResourceBundle.getBundle(resourceBundleName); + result.resourceBundleName = resourceBundleName; + return result; + } + + if ((existingBundleName != resourceBundleName) + && ((existingBundleName == null) + || !existingBundleName.equals(resourceBundleName))) + { + throw new IllegalArgumentException(); + } + } + } + + return result; + } + + + /** + * Creates a new, unnamed logger. Unnamed loggers are not + * registered in the namespace of the LogManager, and no special + * security permission is required for changing their state. + * Therefore, untrusted applets are able to modify their private + * logger instance obtained through this method. + * + * <p>The parent of the newly created logger will the the root + * logger, from which the level threshold and the handlers are + * inherited. + */ + public static Logger getAnonymousLogger() + { + return getAnonymousLogger(null); + } + + + /** + * Creates a new, unnamed logger. Unnamed loggers are not + * registered in the namespace of the LogManager, and no special + * security permission is required for changing their state. + * Therefore, untrusted applets are able to modify their private + * logger instance obtained through this method. + * + * <p>The parent of the newly created logger will the the root + * logger, from which the level threshold and the handlers are + * inherited. + * + * @param resourceBundleName the name of a resource bundle + * for localizing messages, or <code>null</code> + * to indicate that messages do not need to be localized. + * + * @throws java.util.MissingResourceException if + * <code>resourceBundleName</code> is not <code>null</code> + * and no such bundle could be located. + */ + public static Logger getAnonymousLogger(String resourceBundleName) + throws MissingResourceException + { + Logger result; + + result = new Logger(null, resourceBundleName); + result.anonymous = true; + return result; + } + + + /** + * Returns the name of the resource bundle that is being used for + * localizing messages. + * + * @return the name of the resource bundle used for localizing messages, + * or <code>null</code> if the parent's resource bundle + * is used for this purpose. + */ + public synchronized String getResourceBundleName() + { + return resourceBundleName; + } + + + /** + * Returns the resource bundle that is being used for localizing + * messages. + * + * @return the resource bundle used for localizing messages, + * or <code>null</code> if the parent's resource bundle + * is used for this purpose. + */ + public synchronized ResourceBundle getResourceBundle() + { + return resourceBundle; + } + + + /** + * Returns the severity level threshold for this <code>Handler</code>. + * All log records with a lower severity level will be discarded; + * a log record of the same or a higher level will be published + * unless an installed <code>Filter</code> decides to discard it. + * + * @return the severity level below which all log messages will be + * discarded, or <code>null</code> if the logger inherits + * the threshold from its parent. + */ + public synchronized Level getLevel() + { + return level; + } + + + /** + * Returns whether or not a message of the specified level + * would be logged by this logger. + * + * @throws NullPointerException if <code>level</code> + * is <code>null</code>. + */ + public synchronized boolean isLoggable(Level level) + { + if (this.level != null) + return this.level.intValue() <= level.intValue(); + + if (parent != null) + return parent.isLoggable(level); + else + return false; + } + + + /** + * Sets the severity level threshold for this <code>Handler</code>. + * All log records with a lower severity level will be discarded + * immediately. A log record of the same or a higher level will be + * published unless an installed <code>Filter</code> decides to + * discard it. + * + * @param level the severity level below which all log messages + * will be discarded, or <code>null</code> to + * indicate that the logger should inherit the + * threshold from its parent. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void setLevel(Level level) + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.level = level; + } + + + public synchronized Filter getFilter() + { + return filter; + } + + + /** + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void setFilter(Filter filter) + throws SecurityException + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.filter = filter; + } + + + + + /** + * Returns the name of this logger. + * + * @return the name of this logger, or <code>null</code> if + * the logger is anonymous. + */ + public String getName() + { + /* Note that the name of a logger cannot be changed during + * its lifetime, so no synchronization is needed. + */ + return name; + } + + + /** + * Passes a record to registered handlers, provided the record + * is considered as loggable both by {@link #isLoggable(Level)} + * and a possibly installed custom {@link #setFilter(Filter) filter}. + * + * <p>If the logger has been configured to use parent handlers, + * the record will be forwarded to the parent of this logger + * in addition to being processed by the handlers registered with + * this logger. + * + * <p>The other logging methods in this class are convenience methods + * that merely create a new LogRecord and pass it to this method. + * Therefore, subclasses usually just need to override this single + * method for customizing the logging behavior. + * + * @param record the log record to be inspected and possibly forwarded. + */ + public synchronized void log(LogRecord record) + { + if (!isLoggable(record.getLevel())) + return; + + if ((filter != null) && !filter.isLoggable(record)) + return; + + /* If no logger name has been set for the log record, + * use the name of this logger. + */ + if (record.getLoggerName() == null) + record.setLoggerName(name); + + /* Avoid that some other thread is changing the logger hierarchy + * while we are traversing it. + */ + synchronized (LogManager.getLogManager()) + { + Logger curLogger = this; + + do + { + /* The Sun J2SE 1.4 reference implementation seems to call the + * filter only for the logger whose log method is called, + * never for any of its parents. Also, parent loggers publish + * log record whatever their level might be. This is pretty + * weird, but GNU Classpath tries to be as compatible as + * possible to the reference implementation. + */ + for (int i = 0; i < curLogger.handlers.length; i++) + curLogger.handlers[i].publish(record); + + if (curLogger.getUseParentHandlers() == false) + break; + + curLogger = curLogger.getParent(); + } + while (parent != null); + } + } + + + public void log(Level level, String message) + { + if (isLoggable(level)) + log(level, message, (Object[]) null); + } + + + public synchronized void log(Level level, + String message, + Object param) + { + if (isLoggable(level)) + { + StackTraceElement caller = getCallerStackFrame(); + logp(level, + caller != null ? caller.getClassName() : "<unknown>", + caller != null ? caller.getMethodName() : "<unknown>", + message, + param); + } + } + + + public synchronized void log(Level level, + String message, + Object[] params) + { + if (isLoggable(level)) + { + StackTraceElement caller = getCallerStackFrame(); + logp(level, + caller != null ? caller.getClassName() : "<unknown>", + caller != null ? caller.getMethodName() : "<unknown>", + message, + params); + } + } + + + public synchronized void log(Level level, + String message, + Throwable thrown) + { + if (isLoggable(level)) + { + StackTraceElement caller = getCallerStackFrame(); + logp(level, + caller != null ? caller.getClassName() : "<unknown>", + caller != null ? caller.getMethodName() : "<unknown>", + message, + thrown); + } + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message) + { + logp(level, sourceClass, sourceMethod, message, + (Object[]) null); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Object param) + { + logp(level, sourceClass, sourceMethod, message, + new Object[] { param }); + } + + + private synchronized ResourceBundle findResourceBundle() + { + if (resourceBundle != null) + return resourceBundle; + + if (parent != null) + return parent.findResourceBundle(); + + return null; + } + + + private synchronized void logImpl(Level level, + String sourceClass, + String sourceMethod, + String message, + Object[] params) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundle(findResourceBundle()); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setParameters(params); + + log(rec); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Object[] params) + { + logImpl(level, sourceClass, sourceMethod, message, params); + } + + + public synchronized void logp(Level level, + String sourceClass, + String sourceMethod, + String message, + Throwable thrown) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundle(resourceBundle); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setThrown(thrown); + + log(rec); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message) + { + logrb(level, sourceClass, sourceMethod, bundleName, + message, (Object[]) null); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Object param) + { + logrb(level, sourceClass, sourceMethod, bundleName, + message, new Object[] { param }); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Object[] params) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundleName(bundleName); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setParameters(params); + + log(rec); + } + + + public synchronized void logrb(Level level, + String sourceClass, + String sourceMethod, + String bundleName, + String message, + Throwable thrown) + { + LogRecord rec = new LogRecord(level, message); + + rec.setResourceBundleName(bundleName); + rec.setSourceClassName(sourceClass); + rec.setSourceMethodName(sourceMethod); + rec.setThrown(thrown); + + log(rec); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY"); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod, + Object param) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "ENTRY {0}", param); + } + + + public synchronized void entering(String sourceClass, + String sourceMethod, + Object[] params) + { + if (isLoggable(Level.FINER)) + { + StringBuffer buf = new StringBuffer(80); + buf.append("ENTRY"); + for (int i = 0; i < params.length; i++) + { + buf.append(" {"); + buf.append(i); + buf.append('}'); + } + + logp(Level.FINER, sourceClass, sourceMethod, buf.toString(), params); + } + } + + + public synchronized void exiting(String sourceClass, + String sourceMethod) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "RETURN"); + } + + + public synchronized void exiting(String sourceClass, + String sourceMethod, + Object result) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "RETURN {0}", result); + } + + + public synchronized void throwing(String sourceClass, + String sourceMethod, + Throwable thrown) + { + if (isLoggable(Level.FINER)) + logp(Level.FINER, sourceClass, sourceMethod, "THROW", thrown); + } + + + /** + * Logs a message with severity level SEVERE, indicating a serious + * failure that prevents normal program execution. Messages at this + * level should be understandable to an inexperienced, non-technical + * end user. Ideally, they explain in simple words what actions the + * user can take in order to resolve the problem. + * + * @see Level#SEVERE + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * <code>null</code>, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void severe(String message) + { + if (isLoggable(Level.SEVERE)) + log(Level.SEVERE, message); + } + + + /** + * Logs a message with severity level WARNING, indicating a + * potential problem that does not prevent normal program execution. + * Messages at this level should be understandable to an + * inexperienced, non-technical end user. Ideally, they explain in + * simple words what actions the user can take in order to resolve + * the problem. + * + * @see Level#WARNING + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * <code>null</code>, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void warning(String message) + { + if (isLoggable(Level.WARNING)) + log(Level.WARNING, message); + } + + + /** + * Logs a message with severity level INFO. {@link Level#INFO} is + * intended for purely informational messages that do not indicate + * error or warning situations. In the default logging + * configuration, INFO messages will be written to the system + * console. For this reason, the INFO level should be used only for + * messages that are important to end users and system + * administrators. Messages at this level should be understandable + * to an inexperienced, non-technical user. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * <code>null</code>, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void info(String message) + { + if (isLoggable(Level.INFO)) + log(Level.INFO, message); + } + + + /** + * Logs a message with severity level CONFIG. {@link Level#CONFIG} is + * intended for static configuration messages, for example about the + * windowing environment, the operating system version, etc. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource bundle. While + * it is possible to pass <code>null</code>, this is not + * recommended, since a logging message without text is unlikely + * to be helpful. + */ + public synchronized void config(String message) + { + if (isLoggable(Level.CONFIG)) + log(Level.CONFIG, message); + } + + + /** + * Logs a message with severity level FINE. {@link Level#FINE} is + * intended for messages that are relevant for developers using + * the component generating log messages. Examples include minor, + * recoverable failures, or possible inefficiencies. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * <code>null</code>, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void fine(String message) + { + if (isLoggable(Level.FINE)) + log(Level.FINE, message); + } + + + /** + * Logs a message with severity level FINER. {@link Level#FINER} is + * intended for rather detailed tracing, for example entering a + * method, returning from a method, or throwing an exception. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * <code>null</code>, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void finer(String message) + { + if (isLoggable(Level.FINER)) + log(Level.FINER, message); + } + + + /** + * Logs a message with severity level FINEST. {@link Level#FINEST} + * is intended for highly detailed tracing, for example reaching a + * certain point inside the body of a method. + * + * @param message the message text, also used as look-up key if the + * logger is localizing messages with a resource + * bundle. While it is possible to pass + * <code>null</code>, this is not recommended, since + * a logging message without text is unlikely to be + * helpful. + */ + public synchronized void finest(String message) + { + if (isLoggable(Level.FINEST)) + log(Level.FINEST, message); + } + + + /** + * Adds a handler to the set of handlers that get notified + * when a log record is to be published. + * + * @param handler the handler to be added. + * + * @throws NullPointerException if <code>handler</code> + * is <code>null</code>. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void addHandler(Handler handler) + throws SecurityException + { + /* Throw a new NullPointerException if handler is null. */ + handler.getClass(); + + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + if (!handlerList.contains(handler)) + { + handlerList.add(handler); + handlers = getHandlers(); + } + } + + + /** + * Removes a handler from the set of handlers that get notified + * when a log record is to be published. + * + * @param handler the handler to be removed. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted the + * permission to control the logging infrastructure by having + * LoggingPermission("control"). Untrusted code can obtain an + * anonymous logger through the static factory method {@link + * #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + * + * @throws NullPointerException if <code>handler</code> + * is <code>null</code>. + */ + public synchronized void removeHandler(Handler handler) + throws SecurityException + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + /* Throw a new NullPointerException if handler is null. */ + handler.getClass(); + + handlerList.remove(handler); + handlers = getHandlers(); + } + + + /** + * Returns the handlers currently registered for this Logger. + * When a log record has been deemed as being loggable, + * it will be passed to all registered handlers for + * publication. In addition, if the logger uses parent handlers + * (see {@link #getUseParentHandlers() getUseParentHandlers} + * and {@link #setUseParentHandlers(boolean) setUseParentHandlers}, + * the log record will be passed to the parent's handlers. + */ + public synchronized Handler[] getHandlers() + { + /* We cannot return our internal handlers array + * because we do not have any guarantee that the + * caller would not change the array entries. + */ + return (Handler[]) handlerList.toArray(new Handler[handlerList.size()]); + } + + + /** + * Returns whether or not this Logger forwards log records to + * handlers registered for its parent loggers. + * + * @return <code>false</code> if this Logger sends log records + * merely to Handlers registered with itself; + * <code>true</code> if this Logger sends log records + * not only to Handlers registered with itself, but also + * to those Handlers registered with parent loggers. + */ + public synchronized boolean getUseParentHandlers() + { + return useParentHandlers; + } + + + /** + * Sets whether or not this Logger forwards log records to + * handlers registered for its parent loggers. + * + * @param useParentHandlers <code>false</code> to let this + * Logger send log records merely to Handlers registered + * with itself; <code>true</code> to let this Logger + * send log records not only to Handlers registered + * with itself, but also to those Handlers registered with + * parent loggers. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + * + */ + public synchronized void setUseParentHandlers(boolean useParentHandlers) + { + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.useParentHandlers = useParentHandlers; + } + + + /** + * Returns the parent of this logger. By default, the parent is + * assigned by the LogManager by inspecting the logger's name. + * + * @return the parent of this logger (as detemined by the LogManager + * by inspecting logger names), the root logger if no other + * logger has a name which is a prefix of this logger's name, or + * <code>null</code> for the root logger. + */ + public synchronized Logger getParent() + { + return parent; + } + + + /** + * Sets the parent of this logger. Usually, applications do not + * call this method directly. Instead, the LogManager will ensure + * that the tree of loggers reflects the hierarchical logger + * namespace. Basically, this method should not be public at all, + * but the GNU implementation follows the API specification. + * + * @throws NullPointerException if <code>parent</code> is + * <code>null</code>. + * + * @throws SecurityException if this logger is not anonymous, a + * security manager exists, and the caller is not granted + * the permission to control the logging infrastructure by + * having LoggingPermission("control"). Untrusted code can + * obtain an anonymous logger through the static factory method + * {@link #getAnonymousLogger(java.lang.String) getAnonymousLogger}. + */ + public synchronized void setParent(Logger parent) + { + /* Throw a new NullPointerException if parent is null. */ + parent.getClass(); + + if (this == root) + throw new IllegalArgumentException( + "the root logger can only have a null parent"); + + /* An application is allowed to control an anonymous logger + * without having the permission to control the logging + * infrastructure. + */ + if (!anonymous) + LogManager.getLogManager().checkAccess(); + + this.parent = parent; + } + + /** + * Gets the StackTraceElement of the first class that is not this class. + * That should be the initial caller of a logging method. + * @return caller of the initial logging method or null if unknown. + */ + private native StackTraceElement getCallerStackFrame(); + + /** + * Reset and close handlers attached to this logger. This function is package + * private because it must only be avaiable to the LogManager. + */ + void resetLogger() + { + for (int i = 0; i < handlers.length; i++) + { + handlers[i].close(); + handlerList.remove(handlers[i]); + } + handlers = getHandlers(); + } +} diff --git a/gcc-4.2.1/libjava/java/util/logging/natLogger.cc b/gcc-4.2.1/libjava/java/util/logging/natLogger.cc new file mode 100644 index 000000000..5c68b1722 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/logging/natLogger.cc @@ -0,0 +1,49 @@ +// natLogger.cc - Native part of Logger class. + +/* Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation + + This Logger is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the Logger "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <string.h> + +#pragma implementation "Logger.h" + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> + +#include <java/lang/Object.h> +#include <java/lang/Class.h> +#include <java/util/logging/Logger.h> +#include <java/lang/StackTraceElement.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> + +using namespace java::util::logging; + +java::lang::StackTraceElement* +java::util::logging::Logger::getCallerStackFrame () +{ + jclass klass = NULL; + _Jv_Method *meth = NULL; + _Jv_StackTrace::GetCallerInfo (&Logger::class$, &klass, &meth); + + jstring meth_name = NULL; + jstring klass_name = NULL; + if (klass != NULL) + klass_name = klass->getName(); + if (meth != NULL) + meth_name = _Jv_NewStringUtf8Const (meth->name); + + java::lang::StackTraceElement *e + = new java::lang::StackTraceElement + (JvNewStringUTF (""), 0, klass_name, meth_name, false); + + return e; +} diff --git a/gcc-4.2.1/libjava/java/util/natResourceBundle.cc b/gcc-4.2.1/libjava/java/util/natResourceBundle.cc new file mode 100644 index 000000000..e8d4fb4fd --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/natResourceBundle.cc @@ -0,0 +1,29 @@ +/* Copyright (C) 2002, 2003, 2005 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@redhat.com> + +#include <config.h> + +#include <gcj/cni.h> +#include <jvm.h> +#include <java-stack.h> +#include <java/util/ResourceBundle.h> +#include <java/lang/ClassLoader.h> +#include <java/lang/Class.h> + +using namespace java::lang; + +java::lang::ClassLoader * +java::util::ResourceBundle::getCallingClassLoader () +{ + jclass caller = _Jv_StackTrace::GetCallingClass (&ResourceBundle::class$); + if (caller) + return caller->getClassLoaderInternal(); + return NULL; +} diff --git a/gcc-4.2.1/libjava/java/util/natVMTimeZone.cc b/gcc-4.2.1/libjava/java/util/natVMTimeZone.cc new file mode 100644 index 000000000..d45ebf978 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/natVMTimeZone.cc @@ -0,0 +1,145 @@ +// natVMTimeZone.cc -- Native side of VMTimeZone class. + +/* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006 + Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +#include <config.h> +#include <platform.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/util/VMTimeZone.h> +#include <java/lang/Character.h> +#include <java/lang/Integer.h> + +#include <stdio.h> + +#if TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <string.h> + +/** + * This method returns a time zone id string which is in the form + * (standard zone name) or (standard zone name)(GMT offset) or + * (standard zone name)(GMT offset)(daylight time zone name). The + * GMT offset can be in seconds, or where it is evenly divisible by + * 3600, then it can be in hours. The offset must be the time to + * add to the local time to get GMT. If a offset is given and the + * time zone observes daylight saving then the (daylight time zone + * name) must also be given (otherwise it is assumed the time zone + * does not observe any daylight savings). + * <p> + * The result of this method is given to getDefaultTimeZone(String) + * which tries to map the time zone id to a known TimeZone. See + * that method on how the returned String is mapped to a real + * TimeZone object. + */ +jstring +java::util::VMTimeZone::getSystemTimeZoneId() +{ + struct tm tim; +#if !defined(HAVE_LOCALTIME_R) || !defined(_POSIX_PTHREAD_SEMANTICS) + struct tm *lt_tim; +#endif +#ifdef HAVE_TM_ZONE + int month; +#endif + time_t current_time; + long tzoffset; + const char *tz1, *tz2; + char *tzid; + + time(¤t_time); +#if defined(HAVE_LOCALTIME_R) && defined(_POSIX_PTHREAD_SEMANTICS) + localtime_r(¤t_time, &tim); +#else + /* Fall back on non-thread safe localtime. */ + lt_tim = localtime(¤t_time); + memcpy(&tim, lt_tim, sizeof (struct tm)); +#endif + mktime(&tim); + +#ifdef HAVE_TM_ZONE + /* We will cycle through the months to make sure we hit dst. */ + month = tim.tm_mon; + tz1 = tz2 = NULL; + while (tz1 == NULL || tz2 == NULL) + { + if (tim.tm_isdst > 0) + tz2 = tim.tm_zone; + else if (tz1 == NULL) + { + tz1 = tim.tm_zone; + month = tim.tm_mon; + } + + if (tz1 == NULL || tz2 == NULL) + { + tim.tm_mon++; + tim.tm_mon %= 12; + } + + if (tim.tm_mon == month && tz2 == NULL) + tz2 = ""; + else + mktime(&tim); + } + /* We want to make sure the tm struct we use later on is not dst. */ + tim.tm_mon = month; + mktime(&tim); +#elif defined (HAVE_TZNAME) + /* If dst is never used, tzname[1] is the empty string. */ + tzset(); + tz1 = tzname[0]; + tz2 = tzname[1]; +#else + /* Some targets have no concept of timezones. Assume GMT without dst. */ + tz1 = "GMT"; + tz2 = ""; +#endif + +#ifdef STRUCT_TM_HAS_GMTOFF + /* tm_gmtoff is the number of seconds that you must add to GMT to get + local time, we need the number of seconds to add to the local time + to get GMT. */ + tzoffset = -1L * tim.tm_gmtoff; +#elif HAVE_UNDERSCORE_TIMEZONE + tzoffset = _timezone; +#elif HAVE_TIMEZONE + /* timezone is secs WEST of UTC. */ + tzoffset = timezone; +#else + /* FIXME: there must be another global if neither tm_gmtoff nor timezone + is available, esp. if tzname is valid. + Richard Earnshaw <rearnsha@arm.com> has suggested using difftime to + calculate between gmtime and localtime (and accounting for possible + daylight savings time) as an alternative. */ + tzoffset = 0L; +#endif + + if ((tzoffset % 3600) == 0) + tzoffset = tzoffset / 3600; + + tzid = (char*) _Jv_Malloc (strlen(tz1) + strlen(tz2) + 6); + sprintf(tzid, "%s%ld%s", tz1, tzoffset, tz2); + jstring retval = JvNewStringUTF (tzid); + _Jv_Free (tzid); + + return retval; +} diff --git a/gcc-4.2.1/libjava/java/util/zip/Deflater.java b/gcc-4.2.1/libjava/java/util/zip/Deflater.java new file mode 100644 index 000000000..8ac8a34a6 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/zip/Deflater.java @@ -0,0 +1,334 @@ +/* Deflater.java - Compress a data stream + Copyright (C) 1999, 2000, 2001, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +import gnu.gcj.RawData; + +/** + * This is the Deflater class. The deflater class compresses input + * with the deflate algorithm described in RFC 1951. It has several + * compression levels and three different strategies described below. + * + * This class is <i>not</i> thread safe. This is inherent in the API, due + * to the split of deflate and setInput. + * + * @author Jochen Hoenicke + * @author Tom Tromey + */ +public class Deflater +{ + /** + * The best and slowest compression level. This tries to find very + * long and distant string repetitions. + */ + public static final int BEST_COMPRESSION = 9; + /** + * The worst but fastest compression level. + */ + public static final int BEST_SPEED = 1; + /** + * The default compression level. + */ + public static final int DEFAULT_COMPRESSION = -1; + /** + * This level won't compress at all but output uncompressed blocks. + */ + public static final int NO_COMPRESSION = 0; + + /** + * The default strategy. + */ + public static final int DEFAULT_STRATEGY = 0; + /** + * This strategy will only allow longer string repetitions. It is + * useful for random data with a small character set. + */ + public static final int FILTERED = 1; + + /** + * This strategy will not look for string repetitions at all. It + * only encodes with Huffman trees (which means, that more common + * characters get a smaller encoding. + */ + public static final int HUFFMAN_ONLY = 2; + + /** + * The compression method. This is the only method supported so far. + * There is no need to use this constant at all. + */ + public static final int DEFLATED = 8; + + /** Compression level. */ + private int level; + + /** Compression strategy. */ + private int strategy; + + /** The zlib stream. */ + private RawData zstream; + + /** True if finished. */ + private boolean is_finished; + + /** `Flush' flag to pass to next call to deflate. */ + private int flush_flag; + + /** + * Creates a new deflater with default compression level. + */ + public Deflater() + { + this(DEFAULT_COMPRESSION, false); + } + + /** + * Creates a new deflater with given compression level. + * @param lvl the compression level, a value between NO_COMPRESSION + * and BEST_COMPRESSION, or DEFAULT_COMPRESSION. + * @exception IllegalArgumentException if lvl is out of range. + */ + public Deflater(int lvl) + { + this(lvl, false); + } + + /** + * Creates a new deflater with given compression level. + * @param lvl the compression level, a value between NO_COMPRESSION + * and BEST_COMPRESSION. + * @param nowrap true, iff we should suppress the deflate header at the + * beginning and the adler checksum at the end of the output. This is + * useful for the GZIP format. + * @exception IllegalArgumentException if lvl is out of range. + */ + public Deflater(int lvl, boolean noHeader) + { + this.strategy = DEFAULT_STRATEGY; + init(lvl, noHeader); + setLevel(lvl); + } + + private native void init(int level, boolean noHeader); + + private native void update(); + + /** + * Resets the deflater. The deflater acts afterwards as if it was + * just created with the same compression level and strategy as it + * had before. + */ + public native void reset(); + + /** + * Frees all objects allocated by the compressor. There's no + * reason to call this, since you can just rely on garbage + * collection. Exists only for compatibility against Sun's JDK, + * where the compressor allocates native memory. + * If you call any method (even reset) afterwards the behaviour is + * <i>undefined</i>. + * @deprecated Just clear all references to deflater instead. + */ + public native void end(); + + /** + * Gets the current adler checksum of the data that was processed so + * far. + */ + public native int getAdler(); + + /** + * Gets the number of input bytes processed so far. + */ + public native int getTotalIn(); + + /** + * Gets the number of output bytes so far. + */ + public native int getTotalOut(); + + /** + * Finalizes this object. + */ + protected void finalize() + { + end(); + } + + /** + * Finishes the deflater with the current input block. It is an error + * to give more input after this method was called. This method must + * be called to force all bytes to be flushed. + */ + public native void finish(); + + /** + * Returns true iff the stream was finished and no more output bytes + * are available. + */ + public synchronized boolean finished() + { + return is_finished; + } + + /** + * Returns true, if the input buffer is empty. + * You should then call setInput(). <br> + * + * <em>NOTE</em>: This method can also return true when the stream + * was finished. + */ + public native boolean needsInput(); + + /** + * Sets the data which should be compressed next. This should be only + * called when needsInput indicates that more input is needed. + * If you call setInput when needsInput() returns false, the + * previous input that is still pending will be thrown away. + * The given byte array should not be changed, before needsInput() returns + * true again. + * This call is equivalent to <code>setInput(input, 0, input.length)</code>. + * @param input the buffer containing the input data. + * @exception IllegalStateException if the buffer was finished() or ended(). + */ + public void setInput(byte[] input) + { + setInput(input, 0, input.length); + } + + /** + * Sets the data which should be compressed next. This should be + * only called when needsInput indicates that more input is needed. + * The given byte array should not be changed, before needsInput() returns + * true again. + * @param input the buffer containing the input data. + * @param off the start of the data. + * @param len the length of the data. + * @exception IllegalStateException if the buffer was finished() or ended() + * or if previous input is still pending. + */ + public native void setInput(byte[] input, int off, int len); + + /** + * Sets the compression level. There is no guarantee of the exact + * position of the change, but if you call this when needsInput is + * true the change of compression level will occur somewhere near + * before the end of the so far given input. + * @param lvl the new compression level. + */ + public synchronized void setLevel(int lvl) + { + if (lvl != -1 && (lvl < 0 || lvl > 9)) + throw new IllegalArgumentException(); + level = (lvl == -1) ? 6 : lvl; + update(); + } + + /** + * Sets the compression strategy. Strategy is one of + * DEFAULT_STRATEGY, HUFFMAN_ONLY and FILTERED. For the exact + * position where the strategy is changed, the same as for + * setLevel() applies. + * @param stgy the new compression strategy. + */ + public synchronized void setStrategy(int stgy) + { + if (stgy != DEFAULT_STRATEGY && stgy != FILTERED + && stgy != HUFFMAN_ONLY) + throw new IllegalArgumentException(); + strategy = stgy; + update(); + } + + /** + * Deflates the current input block to the given array. It returns + * the number of bytes compressed, or 0 if either + * needsInput() or finished() returns true or length is zero. + * @param output the buffer where to write the compressed data. + */ + public int deflate(byte[] output) + { + return deflate(output, 0, output.length); + } + + /** + * Deflates the current input block to the given array. It returns + * the number of bytes compressed, or 0 if either + * needsInput() or finished() returns true or length is zero. + * @param output the buffer where to write the compressed data. + * @param offset the offset into the output array. + * @param length the maximum number of bytes that may be written. + * @exception IllegalStateException if end() was called. + * @exception IndexOutOfBoundsException if offset and/or length + * don't match the array length. + */ + public native int deflate(byte[] output, int off, int len); + + /** + * Sets the dictionary which should be used in the deflate process. + * This call is equivalent to <code>setDictionary(dict, 0, + * dict.length)</code>. + * @param dict the dictionary. + * @exception IllegalStateException if setInput () or deflate () + * were already called or another dictionary was already set. + */ + public void setDictionary(byte[] dict) + { + setDictionary(dict, 0, dict.length); + } + + /** + * Sets the dictionary which should be used in the deflate process. + * The dictionary should be a byte array containing strings that are + * likely to occur in the data which should be compressed. The + * dictionary is not stored in the compressed output, only a + * checksum. To decompress the output you need to supply the same + * dictionary again. + * @param dict the dictionary. + * @param offset an offset into the dictionary. + * @param length the length of the dictionary. + * @exception IllegalStateException if setInput () or deflate () were + * already called or another dictionary was already set. + */ + public native void setDictionary(byte[] buf, int off, int len); + + // Classpath's compression library supports flushing, but we + // don't. So this is a no-op here. + void flush() + { + } +} diff --git a/gcc-4.2.1/libjava/java/util/zip/Inflater.java b/gcc-4.2.1/libjava/java/util/zip/Inflater.java new file mode 100644 index 000000000..c51cde802 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/zip/Inflater.java @@ -0,0 +1,269 @@ +/* Inflater.java - Decompress a data stream + Copyright (C) 1999, 2000, 2001, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.util.zip; + +import gnu.gcj.RawData; + +/* Written using on-line Java Platform 1.2 API Specification + * and JCL book. + * Believed complete and correct. + */ + +/** + * Inflater is used to decompress data that has been compressed according + * to the "deflate" standard described in rfc1950. + * + * The usage is as following. First you have to set some input with + * <code>setInput()</code>, then inflate() it. If inflate doesn't + * inflate any bytes there may be three reasons: + * <ul> + * <li>needsInput() returns true because the input buffer is empty. + * You have to provide more input with <code>setInput()</code>. + * NOTE: needsInput() also returns true when, the stream is finished. + * </li> + * <li>needsDictionary() returns true, you have to provide a preset + * dictionary with <code>setDictionary()</code>.</li> + * <li>finished() returns true, the inflater has finished.</li> + * </ul> + * Once the first output byte is produced, a dictionary will not be + * needed at a later stage. + * + * @author John Leuner, Jochen Hoenicke + * @author Tom Tromey + * @date May 17, 1999 + * @since JDK 1.1 + */ +public class Inflater +{ + // The zlib stream. + private RawData zstream; + + // True if finished. + private boolean is_finished; + + // True if dictionary needed. + private boolean dict_needed; + + /** + * Creates a new inflater. + */ + public Inflater () + { + this (false); + } + + /** + * Creates a new inflater. + * @param nowrap true if no header and checksum field appears in the + * stream. This is used for GZIPed input. For compatibility with + * Sun JDK you should provide one byte of input more than needed in + * this case. + */ + public Inflater (boolean noHeader) + { + init (noHeader); + } + + /** + * Finalizes this object. + */ + protected void finalize () + { + end (); + } + + /** + * Frees all objects allocated by the inflater. There's no reason + * to call this, since you can just rely on garbage collection (even + * for the Sun implementation). Exists only for compatibility + * with Sun's JDK, where the compressor allocates native memory. + * If you call any method (even reset) afterwards the behaviour is + * <i>undefined</i>. + * @deprecated Just clear all references to inflater instead. + */ + public native void end (); + + /** + * Returns true, if the inflater has finished. This means, that no + * input is needed and no output can be produced. + */ + public synchronized boolean finished () + { + return is_finished; + } + + /** + * Gets the adler checksum. This is either the checksum of all + * uncompressed bytes returned by inflate(), or if needsDictionary() + * returns true (and thus no output was yet produced) this is the + * adler checksum of the expected dictionary. + * @returns the adler checksum. + */ + public native int getAdler (); + + /** + * Gets the number of unprocessed input. Useful, if the end of the + * stream is reached and you want to further process the bytes after + * the deflate stream. + * @return the number of bytes of the input which were not processed. + */ + public native int getRemaining (); + + /** + * Gets the total number of processed compressed input bytes. + * @return the total number of bytes of processed input bytes. + */ + public native int getTotalIn (); + + /** + * Gets the total number of output bytes returned by inflate(). + * @return the total number of output bytes. + */ + public native int getTotalOut (); + + /** + * Inflates the compressed stream to the output buffer. If this + * returns 0, you should check, whether needsDictionary(), + * needsInput() or finished() returns true, to determine why no + * further output is produced. + * @param buffer the output buffer. + * @return the number of bytes written to the buffer, 0 if no further + * output can be produced. + * @exception DataFormatException if deflated stream is invalid. + * @exception IllegalArgumentException if buf has length 0. + */ + public int inflate (byte[] buf) throws DataFormatException + { + return inflate (buf, 0, buf.length); + } + + /** + * Inflates the compressed stream to the output buffer. If this + * returns 0, you should check, whether needsDictionary(), + * needsInput() or finished() returns true, to determine why no + * further output is produced. + * @param buffer the output buffer. + * @param off the offset into buffer where the output should start. + * @param len the maximum length of the output. + * @return the number of bytes written to the buffer, 0 if no further + * output can be produced. + * @exception DataFormatException if deflated stream is invalid. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public native int inflate (byte[] buf, int off, int len) + throws DataFormatException; + + private native void init (boolean noHeader); + + /** + * Returns true, if a preset dictionary is needed to inflate the input. + */ + public synchronized boolean needsDictionary () + { + return dict_needed; + } + + /** + * Returns true, if the input buffer is empty. + * You should then call setInput(). <br> + * + * <em>NOTE</em>: This method also returns true when the stream is finished. + */ + public synchronized boolean needsInput () + { + return getRemaining () == 0; + } + + /** + * Resets the inflater so that a new stream can be decompressed. All + * pending input and output will be discarded. + */ + public native void reset (); + + /** + * Sets the preset dictionary. This should only be called, if + * needsDictionary() returns true and it should set the same + * dictionary, that was used for deflating. The getAdler() + * function returns the checksum of the dictionary needed. + * @param buffer the dictionary. + * @exception IllegalStateException if no dictionary is needed. + * @exception IllegalArgumentException if the dictionary checksum is + * wrong. + */ + public void setDictionary (byte[] buf) + { + setDictionary (buf, 0, buf.length); + } + + /** + * Sets the preset dictionary. This should only be called, if + * needsDictionary() returns true and it should set the same + * dictionary, that was used for deflating. The getAdler() + * function returns the checksum of the dictionary needed. + * @param buffer the dictionary. + * @param off the offset into buffer where the dictionary starts. + * @param len the length of the dictionary. + * @exception IllegalStateException if no dictionary is needed. + * @exception IllegalArgumentException if the dictionary checksum is + * wrong. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public native void setDictionary (byte[] buf, int off, int len); + + /** + * Sets the input. This should only be called, if needsInput() + * returns true. + * @param buffer the input. + * @exception IllegalStateException if no input is needed. + */ + public void setInput (byte[] buf) + { + setInput (buf, 0, buf.length); + } + + /** + * Sets the input. This should only be called, if needsInput() + * returns true. + * @param buffer the input. + * @param off the offset into buffer where the input starts. + * @param len the length of the input. + * @exception IllegalStateException if no input is needed. + * @exception IndexOutOfBoundsException if the off and/or len are wrong. + */ + public native void setInput (byte[] buf, int off, int len); +} diff --git a/gcc-4.2.1/libjava/java/util/zip/natDeflater.cc b/gcc-4.2.1/libjava/java/util/zip/natDeflater.cc new file mode 100644 index 000000000..23e1201b5 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/zip/natDeflater.cc @@ -0,0 +1,216 @@ +// natDeflater.cc - Implementation of Deflater native methods. + +/* Copyright (C) 1999, 2002 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@cygnus.com> + +#include <config.h> + +#include <zlib.h> +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/util/zip/Deflater.h> +#include <java/util/zip/DataFormatException.h> + +#include <java/lang/InternalError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> + +extern void *_Jv_ZMalloc (void *, uInt nitems, uInt size); +extern void _Jv_ZFree (void *, void *addr); + + + +jint +java::util::zip::Deflater::deflate (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + throw new java::lang::NullPointerException; + if (off < 0 || len < 0 || off + len > buf->length) + throw new java::lang::ArrayIndexOutOfBoundsException; + + if (len == 0) + return 0; + + s->next_out = (Bytef *) (elements (buf) + off); + s->avail_out = len; + + switch (::deflate (s, flush_flag)) + { + case Z_STREAM_END: + is_finished = true; + if (s->avail_out == (unsigned int) len) + return -1; + break; + + case Z_STREAM_ERROR: + case Z_BUF_ERROR: + // FIXME? + throw new java::lang::InternalError; + break; + + case Z_OK: + break; + } + + return len - s->avail_out; +} + +void +java::util::zip::Deflater::end () +{ + JvSynchronize sync (this); + // Just ignore errors. + deflateEnd ((z_streamp) zstream); + _Jv_Free (zstream); + zstream = NULL; +} + +void +java::util::zip::Deflater::finish () +{ + JvSynchronize sync (this); + flush_flag = Z_FINISH; +} + +jint +java::util::zip::Deflater::getAdler () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->adler; +} + +jint +java::util::zip::Deflater::getTotalIn () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_in; +} + +jint +java::util::zip::Deflater::getTotalOut () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_out; +} + +jboolean +java::util::zip::Deflater::needsInput () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->avail_in == 0; +} + +void +java::util::zip::Deflater::reset () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + // Just ignore errors. + deflateReset (s); + s->avail_in = 0; + flush_flag = 0; + is_finished = false; +} + +void +java::util::zip::Deflater::setDictionary (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + throw new java::lang::NullPointerException; + if (off < 0 || len < 0 || off + len > buf->length) + throw new java::lang::ArrayIndexOutOfBoundsException; + + // Ignore errors. + deflateSetDictionary (s, (Bytef *) (elements (buf) + off), len); +} + +void +java::util::zip::Deflater::setInput (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + throw new java::lang::NullPointerException; + if (off < 0 || len < 0 || off + len > buf->length) + throw new java::lang::ArrayIndexOutOfBoundsException; + + s->next_in = (Bytef *) (elements (buf) + off); + s->avail_in = len; +} + +void +java::util::zip::Deflater::update () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + int strat = Z_DEFAULT_STRATEGY; + switch (strategy) + { + case DEFAULT_STRATEGY: + strat = Z_DEFAULT_STRATEGY; + break; + case FILTERED: + strat = Z_FILTERED; + break; + case HUFFMAN_ONLY: + strat = Z_HUFFMAN_ONLY; + break; + default: + JvFail ("unexpected strategy"); + } + + // Ignore errors. + deflateParams (s, level, strat); +} + +void +java::util::zip::Deflater::init (jint level, jboolean no_header) +{ + z_stream_s *stream = (z_stream_s *) _Jv_Malloc (sizeof (z_stream_s)); + stream->next_in = Z_NULL; + stream->avail_in = 0; + stream->zalloc = _Jv_ZMalloc; + stream->zfree = _Jv_ZFree; + stream->opaque = NULL; + + // Handle NO_HEADER using undocumented zlib feature. + int wbits = MAX_WBITS; + if (no_header) + wbits = - wbits; + +#define DEFAULT_MEM_LEVEL 8 + if (deflateInit2 (stream, level, Z_DEFLATED, wbits, + DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) + { + jstring msg = NULL; + if (stream->msg != NULL) + msg = JvNewStringLatin1 (stream->msg); + throw new java::lang::InternalError (msg); + } + + zstream = reinterpret_cast<gnu::gcj::RawData *> (stream); + is_finished = false; + flush_flag = 0; +} diff --git a/gcc-4.2.1/libjava/java/util/zip/natInflater.cc b/gcc-4.2.1/libjava/java/util/zip/natInflater.cc new file mode 100644 index 000000000..69de6c335 --- /dev/null +++ b/gcc-4.2.1/libjava/java/util/zip/natInflater.cc @@ -0,0 +1,214 @@ +// natInflater.cc - Implementation of Inflater native methods. + +/* Copyright (C) 1999, 2002 Free Software Foundation + + This file is part of libgcj. + +This software is copyrighted work licensed under the terms of the +Libgcj License. Please consult the file "LIBGCJ_LICENSE" for +details. */ + +// Written by Tom Tromey <tromey@cygnus.com> + +#include <config.h> + +#include <zlib.h> +#include <stdlib.h> + +#include <gcj/cni.h> +#include <jvm.h> + +#include <java/util/zip/Inflater.h> +#include <java/util/zip/DataFormatException.h> + +#include <java/lang/InternalError.h> +#include <java/lang/NullPointerException.h> +#include <java/lang/ArrayIndexOutOfBoundsException.h> +#include <java/lang/OutOfMemoryError.h> + + + +// A couple of helper functions used to interface with zlib's +// allocation. + +void * +_Jv_ZMalloc (void *, uInt nitems, uInt size) +{ + return _Jv_Malloc (nitems * size); +} + +void +_Jv_ZFree (void *, void *addr) +{ + _Jv_Free (addr); +} + + + +void +java::util::zip::Inflater::end () +{ + JvSynchronize sync (this); + // Just ignore errors. + inflateEnd ((z_streamp) zstream); + _Jv_Free (zstream); + zstream = NULL; +} + +jint +java::util::zip::Inflater::getAdler () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->adler; +} + +jint +java::util::zip::Inflater::getRemaining () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->avail_in; +} + +jint +java::util::zip::Inflater::getTotalIn () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_in; +} + +jint +java::util::zip::Inflater::getTotalOut () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + return s->total_out; +} + +jint +java::util::zip::Inflater::inflate (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + throw new java::lang::NullPointerException; + if (off < 0 || len < 0 || off + len > buf->length) + throw new java::lang::ArrayIndexOutOfBoundsException; + + if (len == 0) + return 0; + + s->next_out = (Bytef *) (elements (buf) + off); + s->avail_out = len; + + switch (::inflate (s, Z_SYNC_FLUSH)) + { + case Z_BUF_ERROR: + /* Using the no_header option, zlib requires an extra padding byte at the + end of the stream in order to successfully complete decompression (see + zlib/contrib/minizip/unzip.c). We don't do this, so can end up with a + Z_BUF_ERROR at the end of a stream when zlib has completed inflation + and there's no more input. Thats not a problem. */ + if (s->avail_in != 0) + throw new java::lang::InternalError; + // Fall through. + + case Z_STREAM_END: + is_finished = true; + if (s->avail_out == (unsigned int) len) + return -1; + break; + + case Z_NEED_DICT: + dict_needed = true; + break; + + case Z_DATA_ERROR: + throw new java::util::zip::DataFormatException + (s->msg == NULL ? NULL : JvNewStringLatin1 (s->msg)); + break; + + case Z_MEM_ERROR: + throw new java::lang::OutOfMemoryError; + break; + + case Z_OK: + break; + } + + return len - s->avail_out; +} + +void +java::util::zip::Inflater::reset () +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + // Just ignore errors. + inflateReset (s); + s->avail_in = 0; + is_finished = false; + dict_needed = false; +} + +void +java::util::zip::Inflater::setDictionary (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + throw new java::lang::NullPointerException; + if (off < 0 || len < 0 || off + len > buf->length) + throw new java::lang::ArrayIndexOutOfBoundsException; + + // Ignore errors. + inflateSetDictionary (s, (Bytef *) (elements (buf) + off), len); + dict_needed = false; +} + +void +java::util::zip::Inflater::setInput (jbyteArray buf, jint off, jint len) +{ + JvSynchronize sync (this); + z_streamp s = (z_streamp) zstream; + + if (! buf) + throw new java::lang::NullPointerException; + if (off < 0 || len < 0 || off + len > buf->length) + throw new java::lang::ArrayIndexOutOfBoundsException; + + s->next_in = (Bytef *) (elements (buf) + off); + s->avail_in = len; +} + +void +java::util::zip::Inflater::init (jboolean no_header) +{ + z_stream_s *stream = (z_stream_s *) _Jv_Malloc (sizeof (z_stream_s)); + stream->next_in = Z_NULL; + stream->avail_in = 0; + stream->zalloc = _Jv_ZMalloc; + stream->zfree = _Jv_ZFree; + stream->opaque = NULL; + + // Handle NO_HEADER using undocumented zlib feature. + int wbits = MAX_WBITS; + if (no_header) + wbits = - wbits; + + if (inflateInit2 (stream, wbits) != Z_OK) + { + jstring msg = NULL; + if (stream->msg != NULL) + msg = JvNewStringLatin1 (stream->msg); + throw new java::lang::InternalError (msg); + } + + zstream = reinterpret_cast<gnu::gcj::RawData *> (stream); + is_finished = false; + dict_needed = false; +} |
